我最近发现onActivityResult已弃用。我们该怎么处理呢?

有什么替代方案吗?


当前回答

这就是我如何替换多个requestCodes(把这段代码放在你的活动中):

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

其他回答

我的目标是用最少的代码更改重用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()
    }
}

我在我的项目中使用匕首,我在需要的地方注入了包装器

@Inject
lateinit var activityResultLauncher: ActivityResultLauncherWrapper

但是包装器也可以直接实例化:

val activityResultLauncher = ActivityResultLauncherWrapper()

然后你必须用launchIntentForResult改变startActivityForResult方法。下面是一个从片段中调用它的例子:

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

您将在匿名对象中收到结果。 你可以在Fragment或FragmentActivity中使用OnActivityResultListener,如果你实现了接口,并像这样重构当前的实现:

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

 ...

}

正如我们所知,Kotlin类ActivityResultLauncherWrapper也可以在java代码中使用。在我的项目中也有java类。这里有一个在Fragment中实现回调接口的例子:

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

我希望这有助于为您的案例构建解决方案。

Kotlin版本的@Muntashir阿肯解决方案

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())
  }
 }
}

如果您正在使用SMS同意API,则使用以下代码(Kotlin):

resultLauncher.launch( consentIntent
                            )

    var resultLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
    if (result.resultCode == Activity.RESULT_OK) {
        // There are no request codes
    //    val data: Intent? = result.data
        val message = result.data?.getStringExtra(SmsRetriever.EXTRA_SMS_MESSAGE)
        getOtpFromMessage(message)

    }
}

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.

这就是我如何替换多个requestCodes(把这段代码放在你的活动中):

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