教你用更好的方式在Activity或Fragment之间传递以及返回数据

简介: 教你用更好的方式在Activity或Fragment之间传递以及返回数据

前言


我们都知道在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()
    }
}

代码运行效果

image.png

这么实现有什么优点呢?

  • 一方面针对ResultActivity的启动传参数,更加的具体,启动该Activity,不必要关心postId的key是什么,这样在其他页面需要调用的时候,也只是传入参数,这样对于以后key的重构就不会影响其他部分
  • 另一方面不再需要定义RequestCode,也不错哦
  • 其实它还有个优势哦,看过源码才知道,其实它是结合了lifecycle,在页面销毁的时候,会自动将生成的RequestCode给remove掉

Fragment Result新方式


一张图看清整个通讯的过程

dc0c89f18d5847de93aaa9910d53a562_tplv-k3u1fbpfcp-zoom-in-crop-mark_4536_0_0_0.jpg

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的传递,如果是父子级呢?

6bbd1ff0c5914b6ead37b405b4e78bdb_tplv-k3u1fbpfcp-zoom-in-crop-mark_4536_0_0_0.jpg

如图所示,需要在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更加的简洁好用,也希望能帮助到你,记得点个赞哦。


目录
相关文章
|
6月前
|
Android开发
Android Studio App开发入门之在活动之间传递消息(附源码 超详细必看)(包括显示和隐式Intent,向上一个和下一个Activity发送数据)
Android Studio App开发入门之在活动之间传递消息(附源码 超详细必看)(包括显示和隐式Intent,向上一个和下一个Activity发送数据)
294 0
|
API
原来可以这么操作—修改子View绘制顺序
周一的早上,由于项目的开发做的差不多了,正在等待测试结果的我就开始发呆,思考端午节的去处~
321 0
原来可以这么操作—修改子View绘制顺序
|
Java Linux Android开发
【Android 事件分发】事件分发源码分析 ( 驱动层通过中断传递事件 | WindowManagerService 向 View 层传递事件 )
【Android 事件分发】事件分发源码分析 ( 驱动层通过中断传递事件 | WindowManagerService 向 View 层传递事件 )
291 0
【Android 事件分发】事件分发源码分析 ( 驱动层通过中断传递事件 | WindowManagerService 向 View 层传递事件 )
|
Java Android开发
【JetPack】为现有 Android 项目配置视图绑定 ( ViewBinding ) 模块 ( 视图绑定不影响传统布局操作 | 视图绑定类关联 Activity | 视图绑定类本质 )(一)
【JetPack】为现有 Android 项目配置视图绑定 ( ViewBinding ) 模块 ( 视图绑定不影响传统布局操作 | 视图绑定类关联 Activity | 视图绑定类本质 )(一)
223 0
【JetPack】为现有 Android 项目配置视图绑定 ( ViewBinding ) 模块 ( 视图绑定不影响传统布局操作 | 视图绑定类关联 Activity | 视图绑定类本质 )(一)
|
JSON Java 数据格式
Activity之间使用Intent传递大量数据带来问题
Intent在传递数据时是有大小限制的,这里官方并未详细说明,不过通过实验的方法可以测出数据应该被限制在1MB之(1024KB),采用的是传递某产品详情,发现当数据大小超过1024的时候,程序就会出现闪退、停止运行等异常(不同的手机反应不同),因此可以判断Intent的传输容量在1MB以内,但是根据不同版本、不同厂商,这个值会有区别。
425 0
|
Android开发
【JetPack】为现有 Android 项目配置视图绑定 ( ViewBinding ) 模块 ( 视图绑定不影响传统布局操作 | 视图绑定类关联 Activity | 视图绑定类本质 )(二)
【JetPack】为现有 Android 项目配置视图绑定 ( ViewBinding ) 模块 ( 视图绑定不影响传统布局操作 | 视图绑定类关联 Activity | 视图绑定类本质 )(二)
192 0
|
程序员
将函数放在对象的Value上,然后传给组件执行,实现组件抽象
代码总是可以解决很多问题,在Coding 时,应该及时重构,将代码中的坏味道及时剔除,为以后业务功能开发解决技术债。
676 0
|
Android开发
【android基础】之关于重复类型事件的处理方法
1、 在xml文件中配置android:onClick=“方法名”   2、 在所在activity中定义onClick方法   看下具体的实现: 1.
580 0
|
Android开发
Android 开发中的代码片段(2)复制对象之间的属性值
前言 开发中会遇到这样的一个情况,我们得到一个dto对象,里面有几十个属性值,需要将这几十个属性值的N个通过VO传输另外一个地方,一般我们的做法是: 创建VO类,new vo() 对象,通过vo.set(dto.get)的方式不断的设置值。
1119 0