Activity#onActivityResult被弃用了,该怎么办?
Posted microhex
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Activity#onActivityResult被弃用了,该怎么办?相关的知识,希望对你有一定的参考价值。
1. onActivityResult弃用现象和解决方法
前几天更新了androidX
之后,项目中的onActivityResult
就被声明为@Deprecated
,大概如下图:
由于本人呢,是一个代码洁癖者,看着这个肯定不会很舒服,苦于没有时间,就没有仔细去好好分析,就放在一边呢。今天有点时间,我们就来扒一扒,看看onActivityResult
是如何被弃用了,现在又该如何解决呢?
其实,我们点击Activity#onActivityResult
的源码的时候,就可以看到它自己说明的解决方案:
在Android
代码中,已经提示了需要使用 registerForActivityResult
方法来替代,那么这个方法是什么意思呢?答案在ComponentActivity
定义了:
@NonNull
@Override
public final <I, O> ActivityResultLauncher<I> registerForActivityResult(
@NonNull ActivityResultContract<I, O> contract,
@NonNull ActivityResultCallback<O> callback)
return registerForActivityResult(contract, mActivityResultRegistry, callback);
此时看着参数比较多,有I
又有O
的,其实多看几遍也就那样。对于每一个参数我们可以多聊几下:
ActivityResultContract<I, O> contract
如题我们可以从字面上去翻译他,我们直接叫Activity结果契约类
, 官方的定义为:
A contract specifying that an activity can be called with an input of type I and produce an output of type O Makes calling an activity for result type-safe.
通俗的翻译为 定义了 调用Activity的输入类型I 和 输出类型O
对第二个参数:
ActivityResultCallback<O>
直接翻译就是Activity结果的回调
既然知道了参数,那么我们就来按照介绍,来注册一下:
private val activityResultContract = object : ActivityResultContract<Intent,ActivityResult>()
override fun createIntent(context: Context, input: Intent): Intent = input
override fun parseResult(resultCode: Int, intent: Intent?): ActivityResult = ActivityResult(resultCode,intent)
private val mActivityResultCallback = ActivityResultCallback<ActivityResult>
Log.d("TAG", "show the resultCode: $ActivityResult")
我们一般都是Intent
启动Activity
的,所以此时输入I
应该为Intent
;
如果输出呢,我们一般需要resultCode
和data
,对,就是onActivityResult
中的两个参数:
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?)
此时,正好系统源码给我们提供了一个类,封装了resultCode
和Intent
,那就是androidx.activity.result.ActivityResult
:
@SuppressLint("BanParcelableUsage")
public final class ActivityResult implements Parcelable
private final int mResultCode;
@Nullable
private final Intent mData;
/**
* Create a new instance
*
* @param resultCode status to indicate the success of the operation
* @param data an intent that carries the result data
*/
public ActivityResult(int resultCode, @Nullable Intent data)
mResultCode = resultCode;
mData = data;
由于此时我们定义了activityResultContract
和mActivityResultCallback
,我们现在来注册一下:
class BaseActivity : AppCompatActivity()
private val activityResultContract = object : ActivityResultContract<Intent,ActivityResult>()
override fun createIntent(context: Context, input: Intent): Intent = input
override fun parseResult(resultCode: Int, intent: Intent?): ActivityResult = ActivityResult(resultCode,intent)
private val mActivityResultCallback = ActivityResultCallback<ActivityResult> result -> Log.d("TAG","show the result : $result")
private val launcher : ActivityResultLauncher<Intent> = registerForActivityResult(activityResultContract, mActivityResultCallback)
我们注册了registerForActivityResult
, 此时返回一个ActivityResultLauncher
的对象,其实看它的名字就知道,这个就是启动Activity
的类:
/**
* A launcher for a previously-@link ActivityResultCaller#registerForActivityResult prepared call
* to start the process of executing an @link ActivityResultContract.
*
* @param <I> type of the input required to launch
*/
public abstract class ActivityResultLauncher<I>
public void launch(@SuppressLint("UnknownNullness") I input)
此时,我们就可以使用launcher
去启动Activity
了:
launcher.launch(Intent(this, MainActivity::class.java))
此时,我们就启动成功了,然后在mActivityResultCallback#onActivityResult
中获取我们想要的结果了。
2. 使用 ActivityResultLauncher 替代 onActivityResult 原理
一般,我们使用Activity.startForResult
启动一个Intent,然后我们在Activity#onActivityResult
方法中得到回调,类似于这种:
在使用了 ActivityResultLauncher
之后,逻辑图就大概如下了:
其步骤为:
- 向 ActivityResultRegistry 注册需要启动的 ActivityResultContract 和 ActivityResultCallback,并生成了 ActivityResultLauncher;
- 本来需要Activity.startForResult的调用方法,现在有ActivityResultLauncher代理启动;
- 启动ActivityB完成之后,ActivityA还是会获取到onActivityForResult的回调;
- 此时ActivityA会分发回调数据给 ActivityResultRegistry;
- ActivityResultRegistry会根据 requestCode来来找到目标ActivityResultCallback,从而触发回调,达到调用的效果。
基本上大致的逻辑就差不多将清楚了,有什么不懂的可以直接看看源码,这个源码应该算是比较简单的。
3. 自己使用的心得
如果平时你使用ActivityResultLauncher
作为Demo的话,还是可以使用的,但是真正的项目上,还是需要自己封装的,原因如下:
- 如果你需要在Activity中启动多个不同的Activity,那么你就需要写多个 ActivityResultCallback了,因为按照 ActivityResultLauncher的逻辑,一个Launcher是对应一个ActivityResultCallback的。
- 代码的可读性不够,也主要是第一条的原因,Launcher和ActivityResultCallback是分开的。
为了解决以上的问题,当然也是为了自己调用方便,一般都是自己去封装的,轮子比较多,我在github找到的一个:
https://github.com/TxcA/ManageStartActivity
基本上封装之后可以这么写:
startForResult(MainActivity:class,
putExtra("userName","Tom")
putExtra("location","Shanghai")
) code : Int, data : Intent? ->
// show the result
Log.d("TAG","resultCode : $code, data : $data")
这样看上去就比较优雅了,而且非常的人性化,而且我觉得这个是最符合人思路的代码了。有输入,有参数,然后就直接输出结果了,不需要使用startActivityForResult
,然后又是在onActivityResult
中获取了。
onActivityResult 弃用的意义
其实registerForActivityResult
是基于Jetpack component
发布的,它所做的一切当然还是为了让我们普通开发者能够开发出高质量的应用。onActivityResult
现在也不是不能用,但是Android
拥有了Kotlin
的加持,借助registerForActivityResult
封装出一些高质量,易阅读和理解的代码,都是锦上添花的意义了。
以上是关于Activity#onActivityResult被弃用了,该怎么办?的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 Activity 类以外的 onActivityResult 方法
从另一个 Activity 返回的错误 requestCode onActivityResult
如何从小部件收听已关闭的活动? (onActivityResult只在Activity中)