Метод OnActivityResult устарел. Какая альтернатива?

Недавно я обнаружил, что onActivityResult устарел. Что нам делать, чтобы справиться с этим?

Для этого есть какая-нибудь альтернатива?

Изображение показывает код с зачеркнутым onActivityResult, что указывает на устаревание


person Amir Hossein Ghasemi    schedule 01.07.2020    source источник
comment
если я удалю его, появилась ошибка lint, чтобы добавить супер-вызов!   -  person Amir Hossein Ghasemi    schedule 01.07.2020
comment
Я не знаю, была ли когда-либо устаревшая версия, которая не была бы устаревшей, но я надеюсь на startActivityForResult. Этот новый способ чрезмерно усложняет код и снижает удобочитаемость.   -  person spartygw    schedule 05.03.2021
comment
Google - босс. Но то, как они меняют вещи за короткий промежуток времени, разочаровывает.   -  person AtomX    schedule 09.04.2021
comment
Сейчас сложно протестировать :(   -  person acmpo6ou    schedule 17.04.2021
comment
Я понимаю, почему Google решил пойти по этому пути, он пытается отделить startActivityForResult от жизненного цикла представления. Мне просто хотелось, чтобы это было более элегантно.   -  person Morgan Koh    schedule 06.07.2021


Ответы (15)


Базовое обучение доступно на developer.android.com.

Вот пример того, как преобразовать существующий код в новый:

Старый способ:

    public void openSomeActivityForResult() {
        Intent intent = new Intent(this, SomeActivity.class);
        startActivityForResult(intent, 123);
    }

    @Override
    protected void onActivityResult (int requestCode, int resultCode, Intent data) {
        if (resultCode == Activity.RESULT_OK && requestCode == 123) {
            doSomeOperations();
        }
    }

Новый способ (Java):

    // You can do the assignment inside onAttach or onCreate, i.e, before the activity is displayed
    ActivityResultLauncher<Intent> someActivityResultLauncher = registerForActivityResult(
            new ActivityResultContracts.StartActivityForResult(),
            new ActivityResultCallback<ActivityResult>() {
                @Override
                public void onActivityResult(ActivityResult result) {
                    if (result.getResultCode() == Activity.RESULT_OK) {
                        // There are no request codes
                        Intent data = result.getData();
                        doSomeOperations();
                    }
                }
            });

    public void openSomeActivityForResult() {
        Intent intent = new Intent(this, SomeActivity.class);
        someActivityResultLauncher.launch(intent);
    }

Новый способ (Котлин):

var resultLauncher = registerForActivityResult(StartActivityForResult()) { result ->
    if (result.resultCode == Activity.RESULT_OK) {
        // There are no request codes
        val data: Intent? = result.data
        doSomeOperations()
    }
}

fun openSomeActivityForResult() {
    val intent = Intent(this, SomeActivity::class.java)
    resultLauncher.launch(intent)
}

ИЗМЕНИТЬ. Лучше сделать его более универсальным, чтобы мы могли его повторно использовать. Приведенный ниже фрагмент используется в одном из моих проектов, но учтите, что он недостаточно протестирован и может не охватывать все случаи.

BetterActivityResult.java

import android.content.Intent;
import androidx.activity.result.ActivityResult;
import androidx.activity.result.ActivityResultCaller;
import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContract;
import androidx.activity.result.contract.ActivityResultContracts;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

public class BetterActivityResult<Input, Result> {
    /**
     * Register activity result using a {@link ActivityResultContract} and an in-place activity result callback like
     * the default approach. You can still customise callback using {@link #launch(Object, OnActivityResult)}.
     */
    @NonNull
    public static <Input, Result> BetterActivityResult<Input, Result> registerForActivityResult(
            @NonNull ActivityResultCaller caller,
            @NonNull ActivityResultContract<Input, Result> contract,
            @Nullable OnActivityResult<Result> onActivityResult) {
        return new BetterActivityResult<>(caller, contract, onActivityResult);
    }

    /**
     * Same as {@link #registerForActivityResult(ActivityResultCaller, ActivityResultContract, OnActivityResult)} except
     * the last argument is set to {@code null}.
     */
    @NonNull
    public static <Input, Result> BetterActivityResult<Input, Result> registerForActivityResult(
            @NonNull ActivityResultCaller caller,
            @NonNull ActivityResultContract<Input, Result> contract) {
        return registerForActivityResult(caller, contract, null);
    }

    /**
     * Specialised method for launching new activities.
     */
    @NonNull
    public static BetterActivityResult<Intent, ActivityResult> registerActivityForResult(
            @NonNull ActivityResultCaller caller) {
        return registerForActivityResult(caller, new ActivityResultContracts.StartActivityForResult());
    }

    /**
     * Callback interface
     */
    public interface OnActivityResult<O> {
        /**
         * Called after receiving a result from the target activity
         */
        void onActivityResult(O result);
    }

    private final ActivityResultLauncher<Input> launcher;
    @Nullable
    private OnActivityResult<Result> onActivityResult;

    private BetterActivityResult(@NonNull ActivityResultCaller caller,
                                 @NonNull ActivityResultContract<Input, Result> contract,
                                 @Nullable OnActivityResult<Result> onActivityResult) {
        this.onActivityResult = onActivityResult;
        this.launcher = caller.registerForActivityResult(contract, this::callOnActivityResult);
    }

    public void setOnActivityResult(@Nullable OnActivityResult<Result> onActivityResult) {
        this.onActivityResult = onActivityResult;
    }

    /**
     * Launch activity, same as {@link ActivityResultLauncher#launch(Object)} except that it allows a callback
     * executed after receiving a result from the target activity.
     */
    public void launch(Input input, @Nullable OnActivityResult<Result> onActivityResult) {
        if (onActivityResult != null) {
            this.onActivityResult = onActivityResult;
        }
        launcher.launch(input);
    }

    /**
     * Same as {@link #launch(Object, OnActivityResult)} with last parameter set to {@code null}.
     */
    public void launch(Input input) {
        launch(input, this.onActivityResult);
    }

    private void callOnActivityResult(Result result) {
        if (onActivityResult != null) onActivityResult.onActivityResult(result);
    }
}

При описанном выше подходе вам все равно необходимо зарегистрировать его до или во время запуска активности или прикрепления фрагмента. После определения его можно повторно использовать в действии или фрагменте. Например, если вам нужно начать новые действия в большей части действия, вы можете определить BaseActivity и зарегистрировать новый BetterActivityResult следующим образом:

BaseActivity.java

public class BaseActivity extends AppCompatActivity {
    protected final BetterActivityResult<Intent, ActivityResult> activityLauncher = BetterActivityResult.registerActivityForResult(this);
}

После этого вы можете просто запустить действие из любых дочерних действий, например:

    public void openSomeActivityForResult() {
        Intent intent = new Intent(this, SomeActivity.class);
        activityLauncher.launch(intent, result -> {
            if (result.getResultCode() == Activity.RESULT_OK) {
                // There are no request codes
                Intent data = result.getData();
                doSomeOperations();
            }
        })
    }

Поскольку вы можете установить функцию обратного вызова вместе с Intent, вы можете повторно использовать ее для любых действий.

Точно так же вы также можете использовать другие контракты действий, используя два других конструктора.

person Muntashir Akon    schedule 30.08.2020
comment
Новый способ выглядит излишне сложным по сравнению со старым ... - person drmrbrewer; 11.09.2020
comment
@drmrbrewer избавляет от необходимости поддерживать коды запросов и добавляет возможность запускать тесты. Но я думаю, что его главная проблема - это возможность повторного использования. На мой взгляд, ActivityResultCallback должен быть частью ActivityResultLauncher#launch(), чтобы мы могли повторно использовать его для других целей, например, если бы мне нужно было проверить права доступа к хранилищу для нескольких действий, я мог бы использовать один ActivityResultContracts.RequestPermission() для всех из них. Вы можете реализовать ActivityResultCallback в попытке решить эту проблему, но это будет хуже, чем старый способ, поскольку вам нужно что-то похожее на коды запросов. - person Muntashir Akon; 11.09.2020
comment
Если моя деятельность запускает 2 новых действия для результата, то как я могу отличить его от onActivityResult? - person Bhargav Thanki; 22.01.2021
comment
Единственное удобство, которое я вижу, - это удаление result codes. Нам пришлось добавить разные константы для каждого действия. Иногда мы могли смешивать, и два кода результата становились равными. Это могло привести к различным ошибкам. - person CoolMind; 25.01.2021
comment
@drmrbrewer, согласен. Они сделали ненужный инструмент, который сломал обычное многофункциональное приложение (особенно MVC). Теперь нам нужно создать несколько обратных вызовов вместо одного onActivityResult. Одна активность содержит 10 фрагментов, некоторые из них могут запускать другие активности и возвращать результат. Раньше мы просто возвращали setResult() во фрагменте и обрабатывали в onActivityResult. Теперь нам нужно создать множество обратных вызовов. - person CoolMind; 25.01.2021
comment
Новый способ намного хуже старого. Это нарушает модульность кода и заставляет вас использовать гораздо больше строк кода, чтобы охватить варианты использования предыдущей версии. Устаревание следует использовать, когда вы предоставляете лучший дизайн API, но в Google не рекомендуются вещи произвольно на основе приемлемых решений, не технически обоснованных, которые выглядят основанными на нескольких вариантах использования. - person AndreaF; 28.01.2021
comment
@AndreaF Да, я был абсолютно шокирован, когда Google отказался от ViewPager в пользу ViewPager2, что создало больше проблем, чем решило что-либо. - person Muntashir Akon; 28.01.2021
comment
@MuntashirAkon Список очень длинный, не говоря уже о SAF-maggedon, и не только на платформе Android, и без какого-либо отношения к обратной совместимости интерфейсов API, до такой степени, что теперь я избегаю использовать любую поддерживаемую Google инфраструктуру, когда это возможно, чтобы избежать неприятностей и трат времени при переносе кодовой базы в будущем. - person AndreaF; 28.01.2021
comment
с помощью лямбда версия Java может быть уменьшена до Kotlin - person Isaak Osipovich Dunayevsky; 25.02.2021
comment
Что делать, если деятельность начинается с библиотеки? - person YaMiN; 10.03.2021
comment
@YaMiN Библиотека должна предоставлять своего рода инициализатор, который должен вызываться до или во время создания активности или прикрепления фрагмента. - person Muntashir Akon; 11.03.2021
comment
Действительно ли было необходимо кардинальное изменение ?! Google постоянно меняет вещи, например, какие-то детские подгузники! - person AtomX; 09.04.2021
comment
Обратите внимание, что согласно документации, это решение BetterActivityResult ни в коем случае не должно быть используется - вся причина, по которой onActivityResult является отдельным обратным вызовом, а не лямбда, который вы установили в launch time, заключается в том, что он должен существовать после изменения конфигурации или процесса смерти / восстановления (оба из которых могут произойти, пока другое действие открыто - просто поверните ваше устройство для простого случая). Ваш подход на основе лямбда никогда не сможет правильно обработать эти случаи. - person ianhanniballake; 01.06.2021
comment
@ianhanniballake Верно, результаты могут отображаться некорректно из-за проблем жизненного цикла. Однако, поскольку BetterActivityResult также необходимо инициализировать во время или перед созданием фрагмента / действия, может быть способ обработать их внутри класса. - person Muntashir Akon; 01.06.2021
comment
Я удивлен, что этот API не называется startActivityForResult2. Если вы думаете, что работа с результирующими кодами была утомительной, просто подождите, пока вы получите массу этого беспорядка. - person rmirabelle; 03.06.2021
comment
Я нашел этот пример ZXing нового способа github.com/journeyapps/zxing-android -embedded / issues / 628 - person Foxhunt; 15.06.2021
comment
иногда код результата получает 0 вместо -1 - person PNR; 30.06.2021
comment
@drmrbrewer: что произойдет, если мы продолжим использовать старый способ, похоже, он все еще работает и не попадает в проверку кода: зрелость кода - person DragonFire; 17.07.2021

С этого момента startActivityForResult() устарел, поэтому используйте вместо него новый метод.

Пример Котлина

    fun openActivityForResult() {
        startForResult.launch(Intent(this, AnotherActivity::class.java))
    }


    val startForResult = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { 
    result: ActivityResult ->
        if (result.resultCode == Activity.RESULT_OK) {
            val intent = result.data
            // Handle the Intent
            //do stuff here
        }
    }
person Hardik Hirpara    schedule 01.10.2020

В КОТЛИНЕ я изменил свой код

startActivityForResult(intent, Constants.MY_CODE_REQUEST)

а также

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent) {
    super.onActivityResult(requestCode, resultCode, data)
    if (resultCode == Activity.RESULT_OK) {
        when (requestCode) {
            Constants.MY_CODE_REQUEST -> {
            ...
}

to

registerForActivityResult(StartActivityForResult()) { result ->
    onActivityResult(Constants.MY_CODE_REQUEST, result)
}.launch(intent)

а также

private fun onActivityResult(requestCode: Int, result: ActivityResult) {
    if(result.resultCode == Activity.RESULT_OK) {
        val intent = result.data
        when (requestCode) {
            Constants.MY_CODE_REQUEST -> {
            ...

Надеюсь, у вас это сработает. : D

person Luis Eduardo Moreno    schedule 14.10.2020
comment
onActivityResult из вашего третьего фрагмента кода на registerForActivityResult устарела. - person Filipe Brito; 27.02.2021
comment
@FilipeBrito onActivityResult - это не перезаписываемый метод, это мой собственный метод, имя может быть любым;) - person Luis Eduardo Moreno; 01.03.2021
comment
requestCode по-новому кажется практически бесполезным. - person ThanosFisherman; 21.04.2021
comment
Это неправильный подход. Если вы установите запуск вместе с registerForActivityResult, мы можем столкнуться с ошибкой инициализации. Всегда лучше сначала создать переменную и провести там регистрацию. - person Narendra_Nath; 22.06.2021

New way is : registerForActivityResult

Преимущество:

  1. Новый способ - уменьшить сложность, с которой мы столкнулись, когда вызываем активность из фрагмента или из другой активности.
  2. Легко запросите любое разрешение и получите обратный звонок

В Котлине:

var launchSomeActivity = registerForActivityResult(StartActivityForResult()) { result ->
    if (result.resultCode == Activity.RESULT_OK) {
        val data: Intent? = result.data
        // your operation...
    }
}

fun openYourActivity() {
    val intent = Intent(this, SomeActivity::class.java)
    launchSomeActivity.launch(intent)
}

В Java:

 // Create lanucher variable inside onAttach or onCreate or global
 ActivityResultLauncher<Intent> launchSomeActivity = registerForActivityResult(
     new ActivityResultContracts.StartActivityForResult(),
     new ActivityResultCallback<ActivityResult>() {
              @Override
              public void onActivityResult(ActivityResult result) {
                   if (result.getResultCode() == Activity.RESULT_OK) {
                         Intent data = result.getData();
                         // your operation....
                    }
               }
      });
    
      public void openYourActivity() {
            Intent intent = new Intent(this, SomeActivity.class);
            launchSomeActivity.launch(intent);
      }
person Sanjayrajsinh    schedule 04.03.2021
comment
Что, если кто-то по какой-то причине захочет передать android.content.Intent intent, int requestCode в качестве параметров, например, в устаревшем методе? - person AtomX; 10.04.2021
comment
Не желая слишком сильно менять прежнюю логику до адаптации к новому образу жизни? - person AtomX; 10.04.2021
comment
@AtomX не нужно передавать код запроса, потому что вам нужно создать этот объект запуска для индивидуального вызова, поэтому, если вы хотите вызвать два разных действия, вам нужно создать объект обратного вызова - person Sanjayrajsinh; 11.04.2021
comment
Но мой проект сильно зависит от этого ... Новый способ меняет почти всю логику и усложняет ситуацию ... - person AtomX; 12.04.2021
comment
Как написать onActivityResult () как отдельный, в то время как выполнять другие функции переопределения в java ?. потому что на данный момент он создает сложный способ обработки результата, когда у нас есть более одного результата действия. - person MohanRaj S; 24.04.2021

onActivityResult, startActivityForResult, requestPermissions и onRequestPermissionsResult устарели на androidx.fragment с 1.3.0-alpha04, а не с android.app.Activity.
Вместо этого вы можете использовать _8 _ с _ 9_.

person khcpietro    schedule 17.08.2020

В Java это можно записать примерно так:

ActivityResultLauncher<Intent> startActivityForResult = registerForActivityResult(
    new ActivityResultContracts.StartActivityForResult(),
    result -> {
        if (result.getResultCode() == AppCompatActivity.RESULT_OK) {
            Intent data = result.getData();
            // ...
        }
    }
);

Intent intent = new Intent( ... );
startActivityForResult.launch(intent);
person Martin Zeitler    schedule 21.02.2021
comment
Как я могу обрабатывать несколько requestCode? Пожалуйста помоги. Заранее спасибо. - person hetsgandhi; 10.06.2021

Моей целью было повторно использовать текущую реализацию метода startActivityForResult с минимальными изменениями кода. Для этого я создал класс-оболочку и интерфейс с методом onActivityResultFromLauncher.

interface ActivityResultLauncherWrapper {

    fun launchIntentForResult(activity: FragmentActivity, intent: Intent, requestCode: Int, callBack: OnActivityResultListener)

    fun unregister()

    interface OnActivityResultListener {
        fun onActivityResultFromLauncher(requestCode: Int, resultCode: Int, data: Intent?)
    }
}

class ActivityResultLauncherWrapperImpl : ActivityResultLauncherWrapper {
    private var weakLauncher: WeakReference<ActivityResultLauncher<Intent>>? = null

    override fun launchIntentForResult(
            activity: FragmentActivity,
            intent: Intent,
            requestCode: Int,
            callBack: ActivityResultLauncherWrapper.OnActivityResultListener
    ) {

        weakLauncher = WeakReference(
                activity.registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
                    callBack.onActivityResultFromLauncher(requestCode, result.resultCode, result.data)
                }
        )

        weakLauncher?.get()?.launch(intent)
    }

    override fun unregister() {
        weakLauncher?.get()?.unregister()
    }
}

Я использую Dagger в своем проекте и внедрил обертку там, где она нужна

@Inject
lateinit var activityResultLauncher: ActivityResultLauncherWrapper

Но обертка также может быть создана напрямую:

val activityResultLauncher = ActivityResultLauncherWrapper()

тогда вам нужно изменить метод startActivityForResult на launchIntentForResult. Вот пример вызова из фрагмента:

activityResultLauncher.launchIntentForResult(
        requireActivity(),
        intent,
        REQUEST_CODE_CONSTANT,
        object: ActivityResultLauncherWrapper.OnActivityResultListener {
            override fun onActivityResultFromLauncher(requestCode: Int, resultCode: Int, data: Intent?) {
                /*do something*/
            }
        }
)

Вы получите результат в виде анонимного объекта. Вы можете использовать OnActivityResultListener во фрагменте или FragmentActivity, если вы реализуете интерфейс и реорганизуете текущую реализацию следующим образом:

class MyFragment : Fragment(), OnActivityResultListener {
   
 ...
    
override fun onActivityResultFromLauncher(requestCode: Int, resultCode: Int, data: Intent?) {/*do somthing*/}

 ...

}

Как мы знаем, класс Kotlin ActivityResultLauncherWrapper также можно использовать в java-коде. В моем проекте тоже есть классы java. Вот пример реализации интерфейса обратного вызова во фрагменте:

public class MyFragment extends Fragment implements OnActivityResultListener {
    
...

    @Inject
    ActivityResultLauncherWrapper activityResultLauncher;
//ActivityResultLauncherWrapper activityResultLauncher = new ActivityResultLauncherWrapper()

...

public void launnchActivity(@NotNull Intent intent) {
        activityResultLauncher.launchIntentForResult(requireActivity(), intent, REQUEST_CODE_CONSTANT, this);
    }

...

 @Override
    public void onActivityResultFromLauncher(int requestCode, int resultCode, Intent data) {/*do somthing*/}
...
}

Надеюсь, это поможет найти решение для вашего случая.

person MeLine    schedule 03.02.2021

Ссылка: Kotlin - Выберите изображение из галереи

Самое простое оповещение, которое я нашел на данный момент

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.id.activity_main)

    var ivPhoto = findViewById<ImageView>(R.id.ivPhoto)
    var btnChoosePhoto = findViewById<Button>(R.id.btnChoosePhoto)

    

val getContent = registerForActivityResult(ActivityResultContracts.GetContent())  { uri: Uri? ->
            ivPhoto.setImageURI(uri)    // Handle the returned Uri
        }


    btnChoose.setOnClickListener {
        getContent.launch("image/*")
    }
    
    }
person Allan_Aj5    schedule 30.05.2021

Вот мое решение:

В нашем проекте у нас было более 20 экземпляров startActivityForResult (и onActivityResult).

Мы хотели как можно меньше менять код (и продолжать использовать коды запросов), но при этом представили элегантное решение для будущего использования.

Поскольку многие из нас, разработчиков, используют концепцию BaseActivity, почему бы не воспользоваться ею?

Вот BaseActivity:

abstract class BaseActivity : AppCompatActivity()
{
    private var requestCode: Int = -1
    private var resultHandler: ActivityResultLauncher<Intent>? = null

    override fun onCreate(savedInstanceState: Bundle?)
    {
        super.onCreate(savedInstanceState)
        registerForActivityResult()
    }

    private fun registerForActivityResult()
    {
        if (shouldRegisterForActivityResult())
        {
            resultHandler = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->

                onActivityResult(result.data, requestCode, result.resultCode)
                this.requestCode = -1
            }
        }
    }

   fun startActivityForResult(requestCode: Int, intent: Intent)
   {
       this.requestCode = requestCode
       resultHandler?.launch(intent)
   }

   protected open fun onActivityResult(data: Intent?, requestCode: Int, resultCode: Int)
   {
       // For sub activities
   }

   protected open fun shouldRegisterForActivityResult(): Boolean
   {
      // Sub activities that need the onActivityResult "mechanism", should override this and return true
       return false
   }
}

Вот SubActivity:

class SubActivity : BaseActivity()
{
    companion object
    {
        private const val SOME_REQUEST_CODE = 300
    }

    private fun testActivityResult()
    {
        val intent = Intent(this, OtherActivity::class.java)
        startActivityForResult(SOME_REQUEST_CODE, intent)
    }

    override fun shouldRegisterForActivityResult(): Boolean
    {
        return true
    }

    override fun onActivityResult(data: Intent?, requestCode: Int, resultCode: Int)
    {
        if (requestCode == SOME_REQUEST_CODE)
        {
            // Yes!
        }
    }
}

Надеюсь, это кому-то поможет

person dor506    schedule 01.03.2021

Кажется, что onActivityResult устарел в суперклассе, но вы не упомянули имя суперкласса и compileSdkVersion здесь, в своем вопросе.

В Java и Kotlin каждый класс или метод можно было бы пометить как устаревший, просто добавив к нему @Deprecated, поэтому проверьте свой суперкласс, вы можете расширить неправильный класс.

Когда класс устарел, все его методы также устарели.

Чтобы увидеть быстрое решение, щелкните устаревший метод и нажмите Ctrl+Q в студии Android, чтобы просмотреть документацию по методу, для него должно быть решение.


В моем проекте, использующем androidx и API 29 как compileSdkVersion, этот метод НЕ является устаревшим в действиях и фрагментах.

person ygngy    schedule 08.07.2020
comment
Поскольку теперь в проекте, использующем androidx и API 29 в качестве compileSdkVersion, этот метод также устарел. - person Vlad; 24.12.2020

Вы можете использовать функции расширения для Колтина. Например:

//random utils file
fun Fragment.buildGetContentRequest(function: (Uri) -> Unit): ActivityResultLauncher<String> {
    return this.registerForActivityResult(ActivityResultContracts.GetContent()) {
        function(it)
    }
}

fun Fragment.buildTakePhotoRequest(function: (Boolean) -> Unit): ActivityResultLauncher<Uri> {
    return this.registerForActivityResult(ActivityResultContracts.TakePicture()) {
        function(it)
    }
}

fun Fragment.buildSelectMultipleContentRequest(function: (MutableList<Uri>?) -> Unit): ActivityResultLauncher<String> {
    return this.registerForActivityResult(ActivityResultContracts.GetMultipleContents()) {
        function(it)
    }
}

А потом в вашем фрагменте что-то вроде этого

//your actual fragment logic
class YourFragment : Fragment() {
    //we can assign our request in init process
    private val mRequestSelectFiles = buildSelectMultipleContentRequest { 
        onFilesSelected(it) 
    }


    fun onSelectFiles() {
        val mime = "*/*"
        mRequestSelectFiles.launch(mime)
    }

    fun onFilesSelected(list: MutableList<Uri>?) {
        //your logic
    }
}
person Dwane13    schedule 21.05.2021

Котлинская версия решения @Muntashir Akon

class BetterActivityResult<Input, Result> private constructor(
  caller : ActivityResultCaller,
  contract : ActivityResultContract<Input, Result>,
  var onActivityResult : ((Result) -> Unit)?,
) {

private val launcher : ActivityResultLauncher<Input> =
   caller.registerForActivityResult(contract) { onActivityResult?.invoke(it) }

  /**
   * Launch activity, same as [ActivityResultLauncher.launch] except that it 
   * allows a callback
   * executed after receiving a result from the target activity.
   */
  /**
   * Same as [.launch] with last parameter set to `null`.
   */
  @JvmOverloads
  fun launch(
     input : Input,
     onActivityResult : ((Result) -> Unit)? = this.onActivityResult,
  ) {
    this.onActivityResult = onActivityResult
    launcher.launch(input)
  }

  companion object {
  /**
   * Register activity result using a [ActivityResultContract] and an in-place 
   * activity result callback like
   * the default approach. You can still customise callback using [.launch].
   */
  fun <Input, Result> registerForActivityResult(
    caller : ActivityResultCaller,
    contract : ActivityResultContract<Input, Result>,
    onActivityResult : ((Result) -> Unit)?,
  ) : BetterActivityResult<Input, Result> {
    return BetterActivityResult(caller, contract, onActivityResult)
  }

  /**
   * Same as [.registerForActivityResult] except
   * the last argument is set to `null`.
   */
  fun <Input, Result> registerForActivityResult(
    caller : ActivityResultCaller,
    contract : ActivityResultContract<Input, Result>,
  ) : BetterActivityResult<Input, Result> {
    return registerForActivityResult(caller, contract, null)
  }

  /**
   * Specialised method for launching new activities.
   */
  fun registerActivityForResult(
    caller : ActivityResultCaller,
  ) : BetterActivityResult<Intent, ActivityResult> {
    return registerForActivityResult(caller, StartActivityForResult())
  }
 }
}
person Muhammad Helmi    schedule 24.03.2021

startActivityForResult и onActivityResult устарели в Android 10 API 30, теперь у нас есть новый способ получить результат с помощью registerForActivityResult

resultContract =
    registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
        if (result.resultCode == Activity.RESULT_OK) {
            // There are no request codes
            val country = result.data?.getParcelableExtra<Country>("Country")
            showLiveDemoDialogue(country)
        }
    }

и начать деятельность

val intent = Intent(this, CountriesListActivity::class.java)
        resultContract.launch(intent)

но вы должны зарегистрироваться, прежде чем вызывать запуск и запускать где хотите. в противном случае вы получите это исключение

attempting to register while current state is RESUMED. LifecycleOwners must call register before they are STARTED.
person Mirza Ahmed Baig    schedule 07.04.2021

Другой способ сделать это - сделать это за 3 шага. (Учитывая, что у вас есть startActivityForResult (0 и onActivityResult ())

  1. создать переменную в виде var resultLauncher:ActivityResultLauncher<Intent>
  2. создать частную функцию, в которой вы инициализируете resultLauncher в этом базовом формате
resultLauncher=registerForActivityResult(ActivityResultContracts.StartActivityForResult()){result ->  

// copy paste the code from the onActivityResult replacing resultcode to result.resultCode  

if(result.resultcode==Activity.Result_OK){
val data=result.data // this data variable is of type intent and you can use it 

}else{
//code if you do not get the data 
}
}
  1. Перейдите к строке с startActivityForResult() и замените ее строкой resultLauncher.launch(intent)
person Narendra_Nath    schedule 22.06.2021

Простой пример registerForActivityResult для StartActivityForResult и RequestMultiplePermissions из Activity и Fragment [в Kotlin]

Запрос активности для результата от Activity

registerForActivityResult(
    ActivityResultContracts.StartActivityForResult()
) { activityResult ->
    if (activityResult.resultCode == Activity.RESULT_OK) {
        //...
    }
}

Ознакомьтесь с ActivityResult.

Требуется разрешение от Activity?

registerForActivityResult(
    ActivityResultContracts.RequestMultiplePermissions()
) {
    //it: Map<String, Boolean>
}

Из фрагмента?

Используйте те же методы, но убедитесь, что вы поместили эти реализации в initialization, onAttach(), or onCreate()

person Ngima Sherpa    schedule 25.06.2021