原文链接:https://juejin.im/post/6869045188963074061
前言
我们都知道在Activity之间传递数据很繁琐,为了简化,很多人都是使用过EventBus,可EventBus在追踪问题时反而束手无策,反而增加调试时间,那我们能不能找一个折中的方案,又能简单的实现,又能容易追查问题呢?下面请允许我介绍一下最新的方式在实现数据的Result。
先来看看以前我们都是如何做的
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
if (resultCode == Activity.RESULT_OK) {
when (requestCode) {
REQUEST_PERMISSION -> {
// Do something if success / failed
}
REQUEST_MULTIPLE_PERMISSION -> {
// Do something if success / failed
}
REQUEST_TO_POST -> {
// Parse result and do something
}
}
}
super.onActivityResult(requestCode, resultCode, data)
}
companion object {
const val REQUEST_PERMISSION = 1001
const val REQUEST_MULTIPLE_PERMISSION = 1002
const val REQUEST_TO_POST = 1003
}
复制代码
以前,我们都是这样处理Result,分别定义不同的RequestCode,然后根据这个值来匹配数据。我们再来看看新的方式,然后做个比较
Activity Result新方式
step one
加入依赖
implementation 'androidx.activity:activity-ktx:1.2.0-alpha08'
implementation 'androidx.fragment:fragment-ktx:1.3.0-alpha08'
复制代码
step two
编码
class PostActivityContract(val postId: Int) : ActivityResultContract<Int, String?>() {
override fun createIntent(context: Context, input: Int): Intent {
return Intent(context, ResultActivity::class.java).apply {
putExtra(MainActivity.ID, postId)
}
}
override fun parseResult(resultCode: Int, intent: Intent?): String? {
val data = intent?.getStringExtra(ResultActivity.TITLE)
return if (resultCode == Activity.RESULT_OK && data != null) data
else null
}
}
复制代码
继承ActivityResultContract,并覆写createIntent和parseResult函数,这俩函数很好理解,一个负责创建Intent,一个负责解析Result,那接下来如何使用呢?
class MainActivity : AppCompatActivity() {
private val openPostActivityCustom =
registerForActivityResult(PostActivityContract(2)) { result ->
Log.d("MainActivity", "Result : $result")
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
openPostActivityCustom.launch(1)
}
companion object {
val ID = "id"
}
}
复制代码
只需要调用registerForActivityResult函数,然后在点击事件中,用其返回值调用launch函数即可
class ResultActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_result)
Log.d("ResultActivity", intent.getIntExtra(MainActivity.ID,0).toString())
}
companion object{
val TITLE = "title"
}
fun result(view: View) {
setResult(Activity.RESULT_OK, Intent().apply {
putExtra(TITLE,"title")
})
finish()
}
}
复制代码
代码运行效果
这么实现有什么优点呢?
- 一方面针对ResultActivity的启动传参数,更加的具体,启动该Activity,不必要关心postId的key是什么,这样在其他页面需要调用的时候,也只是传入参数,这样对于以后key的重构就不会影响其他部分
- 另一方面不再需要定义RequestCode,也不错哦
- 其实它还有个优势哦,看过源码才知道,其实它是结合了lifecycle,在页面销毁的时候,会自动将生成的RequestCode给remove掉
Fragment Result新方式
一张图看清整个通讯的过程
Fragment B 使用 FragmentManager 将数据发送到 Fragment A
在生成结果的 Fragment B 中,必须使用相同的 requestKey 在同一 FragmentManager 上设置结果。您可以使用 setFragmentResult() API 来完成此操作:
button.setOnClickListener {
val result = "result"
// Use the Kotlin extension in the fragment-ktx artifact
setResult("requestKey", bundleOf("bundleKey" to result))
}
复制代码
在Fragment A中注册回调结果监听
FragmentManager.setFragmentResultListener(
requestKey,
lifecycleOwner,
FragmentResultListener { requestKey: String, result: Bundle ->
// 处理结果
})
复制代码
这种情况需要注意的就是requestKey,在出去和返回的时候都要保持一致。还有一种情况是,如果有多个数据传递,只会接收到最新的值,更Activity一样,在DESTROYED时,会自动取消listener,以上是同级Fragment的传递,如果是父子级呢?
如图所示,需要在Parent Fragment 调用 childFragmentManager来注册listener
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// We set the listener on the child fragmentManager
childFragmentManager.setResultListener("requestKey") { key, bundle ->
val result = bundle.getString("bundleKey")
// Do something with the result..
}
}
复制代码
这么实现有什么优点呢?
- 完全解耦,无需依赖对方
- 当ON_DESTROY时自动注销
总结
经过这期,主要了解到,最新的Activity和Fragment之间如何用新的方式传递数据,且都是kotlin版本的扩展,java也能用,但kotlin更加的简洁好用,也希望能帮助到你,记得点个赞哦。