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

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

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

31 ответ

Базовое обучение доступно на сайте 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();
        }
    }

Новый способ:

    // 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 code
                        Intent data = result.getIntent();
                        doSomeOperations();
                    }
                }
            });

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

Отныне, 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
    }
}

Новый способ: 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);
      }

При замене устаревшего метода startActivityForResult(...) необходимо выполнить 4 простых шага.

  1. Вместо переопределенного метода onActivityResult(..) -

             ActivityResultLauncher<Intent> activityResultLaunch = registerForActivityResult(
             new ActivityResultContracts.StartActivityForResult(),
             new ActivityResultCallback<ActivityResult>() {
                 @Override
                 public void onActivityResult(ActivityResult result) {
                     if (result.getResultCode() == 123) {
                         // ToDo : Do your stuff...
                     } else if(result.getResultCode() == 321) {
                         // ToDo : Do your stuff...
                     }
                 }
    

    });

Для нескольких пользовательских запросов добавьте условие как

          if (result.getResultCode() == 123) {
..
} else if(result.getResultCode() == 131){
..
} // so on..
  1. Импорт:

             import androidx.activity.result.ActivityResult;
     import androidx.activity.result.ActivityResultCallback;
     import androidx.activity.result.ActivityResultLauncher;
     import androidx.activity.result.contract.ActivityResultContracts;
    
  2. Вместо startActivityForResult (intent, 123) используйте

             Intent intent = new Intent(this, SampleActivity.class);
     activityResultLaunch.launch(intent);
    
  3. В классе SampleActivity.java при возврате к исходной активности код останется таким же, как -

            Intent intent = new Intent();
    setResult(123, intent);
    finish();
    

Удачного кодирования! :)

В 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);

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

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 -> {
            ...
}

ЗА

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

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

Я представляю, как вы кодируете по-старому:

      override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
    super.onActivityResult(requestCode, resultCode, data)
    if (resultCode == Activity.RESULT_CODE) {
        when (requestCode) {
            REQUEST_TAKE_PHOTO -> {
                // handle photo from camera
            }
            REQUEST_PICK_IMAGE_FROM_GALLERY -> {
                // handle image from gallery
            }
        }
    }
}

В новом API вам нужно реализовать результат каждого запроса в отдельном ActivityResultContract:

      val takePhotoForResult = registerForActivityResult(StartActivityForResult()) { result: ActivityResult ->
    if (result.resultCode == Activity.RESULT_OK) {
        val intent = result.data
        // handle photo from camera
    }
}

val pickImageFromGalleryForResult = registerForActivityResult(StartActivityForResult()) { result: ActivityResult ->
    if (result.resultCode == Activity.RESULT_OK) {
        val intent = result.data
        // handle image from gallery
    }
}

Затем вам нужно начать эти действия/намерения следующим образом:

      private fun startTakePhotoActivity() {
    takePhotoForResult.launch(Intent(requireActivity(), TakePhotoActivity::class.java))
}

private fun pickImageFromGallery() {
    val pickIntent = Intent(Intent.ACTION_PICK)
    pickIntent.setDataAndType(
        MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
        "image/*"
    )
    pickImageFromGalleryForResult.launch(pickIntent)
}

Делая это, вы можете избавиться от сотен const val REQUEST_значения в вашем проекте.

onActivityResult, startActivityForResult, requestPermissions, а также onRequestPermissionsResultявляются устаревшими наandroidx.fragment от 1.3.0-alpha04, не на android.app.Activity.
Вместо этого вы можете использовать Activity Result APIs с registerForActivityResult.

Ссылка: 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/*")
    }
    
    }

Здесь я объясняю новый способ

      private val scan =
        registerForActivityResult(ActivityResultContracts.StartActivityForResult())
        { result: ActivityResult ->
            if (result.resultCode == AppCompatActivity.RESULT_OK && result.data != null) {

                var selected_hub = result!!.data!!.getParcelableExtra<ExtendedBluetoothDevice>(Utils.EXTRA_DEVICE)
                Log.d(TAG,"RECONNECT PROCESS "+selected_hub!!.name)
                reconnect(selected_hub!!)

            }
        }

вызовите это из действия или фрагмента

      private fun callScan() {
        val intent = Intent(requireActivity(), ScanningMeshDevices::class.java)
        scan.launch(intent)
    }

Код ниже работает во фрагменте Kotlin для проверки разрешения Bluetooth. Год - 2022

val намерение = намерение (BluetoothAdapter.ACTION_REQUEST_ENABLE)

              registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
            if (result.resultCode == Activity.RESULT_OK) {
                // There are no request codes
                val data: Intent? = result.data
                bluetoothAdapter.enable()
                Toast.makeText(context, "Permission Granted: ", Toast.LENGTH_SHORT).show()
                dynamicButton()
            }
            else{Toast.makeText(context, "You have to enable bluetooth to use this app.", Toast.LENGTH_SHORT).show()}
            
        }.launch(intent)

Моей целью было повторно использовать текущую реализацию метода с минимальными изменениями кода. Для этой цели я создал класс-оболочку и интерфейс с методом 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 в Fragment или 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*/}
...
}

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

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

В нашем проекте у нас было более 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!
        }
    }
}

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

Я понял, как правильно это сделать из фрагмента в Котлине, чтобы захватить изображение и обработать возвращенное растровое изображение. Примерно то же самое и в других случаях.

Во-первых, вы должны зарегистрировать фрагмент для прослушивания результатов активности. Это необходимо сделать перед инициацией фрагмента, что означает создание переменной-члена вместо инициации в функции onCreate.

      class DummyFragment : Fragment() {

  //registering fragment for camera listener
  private val takePhoto = registerForActivityResult(
    ActivityResultContracts.StartActivityForResult()
  ) {
    if (it.resultCode == Activity.RESULT_OK) {
      val imageBitmap = it.data?.extras?.get("data") as Bitmap
      // do your thing with the obtained bitmap
    }
  }

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

}

Затем вызовите намерение камеры, как обычно. И используйте эту созданную выше переменную для запуска намерения.

      override fun onCreate(savedInstanceState: Bundle?) {
  super.onCreate(savedInstanceState)
  someRandomButton.setOnClickListener {
    val takePictureIntent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
    takePhoto.launch(takePictureIntent)
  }
}

Вот как я заменил несколько кодов запроса (поместите этот код в свою активность):

          ActivityResultLauncher<Intent> launchCameraActivity = registerForActivityResult(
        new ActivityResultContracts.StartActivityForResult(),
        new ActivityResultCallback<ActivityResult>() {
            @Override
            public void onActivityResult(ActivityResult result) {
                if (result.getResultCode() == Activity.RESULT_OK) {
                    Intent data = result.getData();
                    Bitmap photoBitmap;
                    if(data != null && data.getExtras() != null){
                        photoBitmap = (Bitmap) data.getExtras().get("data");
                        if (photoBitmap != null) {
                            dataModel.setPhoto(ImageUtil.convert(photoBitmap));
                            imageTaken.setVisibility(View.VISIBLE);
                            imageTaken.setImageBitmap(photoBitmap);
                        }

                    }
                }
            }
        });

ActivityResultLauncher<Intent> launchCameraAndGalleryActivity = registerForActivityResult(
    new ActivityResultContracts.StartActivityForResult(),
    new ActivityResultCallback<ActivityResult>() {
        @Override
        public void onActivityResult(ActivityResult result) {
            if (result.getResultCode() == Activity.RESULT_OK) {
                
                Intent data = result.getData();
                Uri imageUri;
                if (data != null) {
                    imageUri = data.getData();
                    InputStream imageStream;
                    try {
                        imageStream = getContentResolver().openInputStream(imageUri);
                        Bitmap photoBitmap = BitmapFactory.decodeStream(imageStream);
                        dataModel.setOtherImage(ImageUtil.convert(photoBitmap));
                        documentImageTaken.setVisibility(View.VISIBLE);
                        documentImageTaken.setImageBitmap(photoBitmap);
                    }catch (FileNotFoundException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    });

Я запускаю действия следующим образом:

                          Intent photoIntent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
                launchCameraAndGalleryActivity.launch(photoIntent );

Intent galleryIntent= new Intent(Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
    launchCameraActivity.launch(galleryIntent);

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

      //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
    }
}

После застревания на несколько часов. Я понял свою проблему. Поэтому, когда я пытался использовать намерение, я переходил непосредственно к следующему действию без использования входа в систему Google.

Что сработало для меня:

Внутри OnCreate установите onClickListener для кнопки входа:

       btnSignIn.setOnClickListener {
    signIn()
    }

private fun signIn() {
    val intent = client.signInIntent
    mainActivityResultLauncher.launch(intent)
}

В приведенном выше коде я писал о намерении перейти к следующему действию, но мне пришлось написать client.signInIntent

      var mainActivityResultLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()){ result ->

    if(result.resultCode == Activity.RESULT_OK){
        val data = result.data
        val task = GoogleSignIn.getSignedInAccountFromIntent(data)
        try {
            // Google Sign In was successful, authenticate with Firebase
            val account = task.getResult(ApiException::class.java)!!
            Log.d(TAG, "firebaseAuthWithGoogle:" + account.id)
            firebaseAuthWithGoogle(account.idToken!!)
        } catch (e: ApiException) {
            // Google Sign In failed, update UI appropriately
            Log.w(TAG, "Google sign in failed", e)
        }
    }
}

Другой способ сделать это - сделать это за 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)

Делюсь найденным решением

Сначала зарегистрируйте это действие для результата, используя registerForActivityResultЭто вернет объект типа ActivityResultLauncher<Intent!>Как это,

      private val getResult =
        registerForActivityResult(
            ActivityResultContracts.StartActivityForResult()
        ) {
            if (it.resultCode == Activity.RESULT_OK) {
                val value = it.data?.getStringExtra("input")
            }
        }

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

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

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

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

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


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

Ответ dor506 сработал для меня, поскольку я использую BaseActivity в большинстве своих проектов, поэтому мне проще изменить код в одном файле, а не во всех моих действиях. Я написал java-версию этого кода.

Код базовой активности:

      private int requestCode = -1;
private ActivityResultLauncher<Intent> resultHandler = null;

 @Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    mContext = this;

    registerForActivityResult();
}
  private final void registerForActivityResult() {
    if (shouldRegisterForActivityResult()) {
        this.resultHandler = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(),
                new ActivityResultCallback() {

            public void onActivityResult(Object var1) {
                this.onActivityResult((ActivityResult)var1);
            }

            public final void onActivityResult(ActivityResult result) {
                Intrinsics.checkNotNullExpressionValue(result, "result");
                AppActivityClass.onActivityResult(result.getData(), AppActivityClass.this.requestCode, result.getResultCode());
                AppActivityClass.this.requestCode = -1;
            }
        });
    }
}

public final void startActivityForResult(int requestCode, Intent intent) {
    this.requestCode = requestCode;
    if (resultHandler != null) {
        resultHandler.launch(intent);
    }
}

protected static void onActivityResult(Intent intent, int requestCode, int resultCode) {
}

protected Boolean shouldRegisterForActivityResult() {
    return false;
}

Теперь в любой деятельности используйте этот код следующим образом:

       @Override
protected Boolean shouldRegisterForActivityResult() {
    return true;  // this will override the baseactivity method and we can use onactivityresult
}

  private void someMethod(){
    Intent i = new Intent(mContext,SomeOtherClassActivity.class);
    startActivityForResult(101,i);
}

  @Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if (requestCode == 101) {
        if (resultCode == RESULT_OK) {
            //revert from called class
        }
    }
}

В сочетании с приведенным выше ответом у меня есть подход, совместимый со старым способом startActivityForResult(), который продолжает использовать requestCode без изменения старой структуры кода:

ActivityLauncher.класс

      public class ActivityLauncher {

private final ActivityResultLauncher<Intent> launcher;
private ActivityResultCallback<ActivityResult> activityResultCallback;

private ActivityLauncher(@NonNull ActivityResultCaller caller,
                         @NonNull ActivityResultContract<Intent, ActivityResult> contract,
                         @Nullable ActivityResultCallback<ActivityResult> activityResultCallback) {
    this.activityResultCallback = activityResultCallback;
    this.launcher = caller.registerForActivityResult(contract, this::onActivityResult);
}

public static ActivityLauncher registerActivityForResult(
        @NonNull ActivityResultCaller caller) {
    return new ActivityLauncher(caller, new ActivityResultContracts.StartActivityForResult(), null);
}

public void launch(Intent intent, @Nullable ActivityResultCallback<ActivityResult> activityResultCallback) {
    if (activityResultCallback != null) {
        this.activityResultCallback = activityResultCallback;
    }
    launcher.launch(intent);
}

private void onActivityResult(ActivityResult result) {
    if (activityResultCallback != null) activityResultCallback.onActivityResult(result);
}

public interface OnActivityResult {
    void onActivityResultCallback(int requestCode, int resultCode, Intent data);
}

}

Код в BaseActivity.java

      private final ActivityLauncher activityLauncher = ActivityLauncher.registerActivityForResult(this);

public void startActivityForResult(Intent intent, int requestCode, ActivityLauncher.OnActivityResult onActivityResult) {
    activityLauncher.launch(intent, result -> onActivityResult.onActivityResultCallback(requestCode, result.getResultCode(), result.getData()));
}

И, наконец, в каждом Activity , которое расширяет BaseActivity , реализует ActivityLauncher.OnActivityResult и изменяет имя функции переопределения «onActivityResult» на «onActivityResultCallback». Также не забудьте удалить super.onActivityResult()

Как использовать: startActivityForResult(intent, requestCode, this)

Котлин версия 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())
  }
 }
}

Если вы реализуете свое базовое действие таким образом, вы можете продолжить использование startActivityForResult по-старому. Единственное ограничение - вам нужно будет использовать setResult(результат, намерение), чтобы установить результат в своей деятельности. Ключ состоит в том, чтобы позволить результату передать код запроса обратно потребителю результата.

      public class MyBaseActivity extends AppCompatActivity {
    private ActivityResultLauncher<Intent> activityLauncher;
    protected static String ACTIVITY_REQUEST_CODE = "my.activity.request.code";
    protected _originalIntent; 

    public void launchActivityForResult(Intent intent, int requestCode){
        intent.putExtra(UGM_ACTIVITY_REQUEST_CODE, requestCode);
        activityLauncher.launch(intent);
    }

    //
    //In order to be signature compatible for the rest of derived activities, 
    //we will override the deprecated method with our own implementation!
    //
    @SuppressWarnings( "deprecation" )
    public void startActivityForResult(Intent intent, int requestCode){
        launchActivityForResult(intent, requestCode);
    }

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

    _originalIntent = getIntent();
        //set the default result
        setResult(Activity.RESULT_OK, _originalIntent);

        activityLauncher = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), new ActivityResultCallback<ActivityResult>() {
            @Override
            public void onActivityResult(ActivityResult result) {
                Intent intent = result.getData();
                int requestCode = intent.getIntExtra(ACTIVITY_REQUEST_CODE, -1);
                MyBaseActivity.this.onActivityResult(requestCode, result.getResultCode(), intent);
            }
        });
    }

}
      ActivityResultLauncher<Intent> someActivityResultLauncher = registerForActivityResult(
        new ActivityResultContracts.StartActivityForResult(),
        new ActivityResultCallback<ActivityResult>() {
            @Override
            public void onActivityResult(ActivityResult result) {
                if (result.getResultCode() == Activity.RESULT_OK) {

                }
            }
        });

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.

Простой пример 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()

Добавляя к ответам Muntashir Akon и Abhijeet , вы можете изменить новый формат, чтобы он работал как старый формат, передав значения в намерении, например:

      // calling class
....
val i = Intent(this@GEBShopActivity, BarcodeScannerActivity::class.java)
when(loadedFragment){   
   is ShopHomeFragment      -> { i.putExtra("myapp.result.code", CODE_ACTIVITY_SCAN_LIST_MAINT) }
   is ShopListFragment      -> { i.putExtra("myapp.result.code", CODE_ACTIVITY_SCAN_LIST_MAINT) }
   is ShopItemMaintFragment -> { i.putExtra("myapp.result.code", CODE_ACTIVITY_SCAN_ITEM_MAINT) }
   is ShopPriceFragment     -> { i.putExtra("myapp.result.code", CODE_ACTIVITY_PRICE_CAPTURE) }
   is ShopCompareFragment   -> { i.putExtra("myapp.result.code", CODE_ACTIVITY_PRICE_CAPTURE) }
}
shopFragmentLauncher.launch(i)
....
      // called class
....
val resultIntent = Intent()
val bundle = Bundle()
bundle.putStringArrayList("scanned_barcodes", scanned_barcodes)
bundle.putInt("scan_count", scan_count)
resultIntent.putExtras(bundle)
resultIntent.putExtra("myapp.result.code", intent.getIntExtra("myapp.result.code", 0))
setResult(Activity.RESULT_OK, resultIntent)
....

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

2023 Kotlin Ответ, чтобы получить файл .

Пример для тех, кто ищет способ получить изображение из библиотеки изображений и обработать его, потому чтоsuper.onActivityResult(requestCode, resultCode, data)вычеркнуто /устарело

Я получил этот ответ из документов Google , и он работает.

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

К вашему сведению, вы сможете использовать это, чтобы получить любойUri, а не только для изображений. Здесь оно используется ниже.

      import androidx.activity.result.contract.ActivityResultContracts

class MainActivity : AppCompatActivity() {

    lateinit var binding: ActivityMainBinding

    override fun onCreate(savedInstanceState: Bundle?) {
        // ...

        binding.selectPhotoButton.setOnClickListener {
            selectPhoto()
        }
    }

    fun selectPhoto() {

        getContent.launch("image/*") // *** What Google said to do to launch the image library ***
    }

    // *** This is what Google posted to handle the Uri ***
    val getContent = registerForActivityResult(ActivityResultContracts.GetContent()) { uri: Uri? ->

        // Handle the returned Uri

        binding.myImageView.setImageURI(uri)
    }
}

Я использую расширение kotlin, чтобы сделать его очень простым. Добавьте ниже функцию расширения в свой файл Extenstions.kt :

      fun AppCompatActivity.startForResult(intent: Intent,
    onResult: (resultCode: Int, data: Intent?) -> Unit
) {
    this.registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {result ->
        onResult(result.resultCode, result.data)
    }.launch(intent)
}

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

      val i = Intent(this, TargetActivity::class.java)
startForResult(i) { resultCode, data ->
   //put your code here like:
   if (resultCode == RESULT_OK) {
      //your code here...
      }
   }
}

Обновление выше может вызвать исключение ниже:java.lang.IllegalStateException: LifecycleOwner xxxx пытается зарегистрироваться, пока текущее состояние - RESUMED. LifecycleOwners должны позвонить в регистр, прежде чем они НАЧИНАЮТСЯ.

Так что registerForActivityResult следует вызывать заранее, например, до onCreate. Вот альтернативное решение.

Добавьте ниже функцию расширения в файл Extenstions.kt :

      fun AppCompatActivity.registerForResult(onResult: (resultCode: Int, data: Intent?) -> Unit):
        ActivityResultLauncher<Intent> {
    return this.registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
        onResult(result.resultCode, result.data)
    }
}

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

  1. Определите переменную члена класса для каждого действия, требующего результата
      private val myActionResult = registerForResult { resultCode, data ->
   //put your code here like:
   if (resultCode == RESULT_OK) {
      //your code here...
      }
   }
}
  1. Запустить действие
      val i = Intent(this, TargetActivity::class.java)
myActionResult.launch(i)
Другие вопросы по тегам