【Jetpack更新之Fragment】1.3.0-alpha04 来袭,Fragment 间通信的新姿势

本文介绍了Jetpack Fragment 1.3.0-alpha04版本的重要更新,包括API更改、Activity Result API的上位、`prepareCall`的重命名、target fragment API的弃用,以及新引入的更安全的Fragment间数据传递方式。重点讨论了如何在不直接访问目标Fragment实例的情况下进行数据传递,并分析了新的源码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言

fragment 1.3.0-alpha04 发布了,其中有很多变动,其中提供了 fragment 间传递数据的新方式

1.3.0-alpha04 更新

API 更改

首先我们介绍一下 API 更改

  • startActivityForResult()/onActivityResult()requestPermissions()/onRequestPermissionsResult() 弃用

  • prepareCall() 重命名为 registerForActivityResult()

  • target fragment API 被弃用

Activity Result API 上位

由于官方提供了 「Activity Result API」 来替换 「onActivityResult」 机制,因此 fragment 的 startActivityForResult()/onActivityResult()requestPermissions()/onRequestPermissionsResult() 方法被标记弃用了

「Activity Result API」 详情可参考 秉心说 的 是时候丢掉 onActivityResult 了 !

文章介绍的很详尽,这里不再赘述

prepareCall 重命名

值得注意的地方是 prepareCall() 被命名为 registerForActivityResult()

注意:在版本处于 Alpha 版状态时,可以添加、移除或更改 API。因此 Alpha 版本不适合在生产上使用

来自我的另一篇博客

target fragment API 被弃用

其实 target fragment API 早已被弃用

setTargetFragment 被弃用

target fragment 需要直接访问另一个 fragment 的实例,这是十分危险的,因为你不知道目标 fragment 处于什么状态。而且 target fragment 不支持 Navigation

弃用 target fragment API

那么,fragment 之间传递数据更干净的方式是什么呢?

fragment 之间传递数据的新方式

前文提到,在相同的 FragmentManager 中可以使用 target fragment API 来在 fragment 间传递数据,但这种方式需要直接访问目标 fragment 的实例,这很危险,因为目标 fragment 的状态是未知的

因此官方提供了这样的 API,它允许在一个 fragment 上设置结果,并将该结果在 fragment 的适当的生命周期中使用。

这种传递数据的方式适用于 DialogFragment ,Navigation 中的 fragment

此更改还包括 -ktx 扩展功能以确保 kotlin 用户可以将 FragmentResultListener 作为 lambda 传递

FragmentA 源码
FragmentB 源码
demo

源码分析

老规矩,我们沿着官方的 commit log 来看看官方实现该功能的思路

首先,添加了 FragmentResultOwner 这样的的抽象,用于处理 fragment result,其内部有两个方法

  • setResult

  • setResultListener

前者用于发送数据,后者用于接收数据

FragmentResultOwner

而其实现类为 FragmentManager

FragmentManager implement FragmentResultOwner

我们来看看 FragmentManager 两个方法的具体实现

public final void setFragmentResultListener(@NonNull final String requestKey,
        @NonNull final LifecycleOwner lifecycleOwner,
        @Nullable final FragmentResultListener listener) {
    // 设置的 listener 为空时将 requestKey 对应的 listener 移除
    if (listener == null) {
        mResultListeners.remove(requestKey);
        return;
    }

    // 当fragment 处于DESTROYED 状态时 直接 return ,避免了异常
    final Lifecycle lifecycle = lifecycleOwner.getLifecycle();
    if (lifecycle.getCurrentState() == Lifecycle.State.DESTROYED) {
        return;
    }

    // 观察生命周期,fragment started 后接收回调,destroyed 移除回调
    LifecycleEventObserver observer = new LifecycleEventObserver() {
        @Override
        public void onStateChanged(@NonNull LifecycleOwner source,
                @NonNull Lifecycle.Event event) {
            if (event == Lifecycle.Event.ON_START) {
                // once we are started, check for any stored results
                Bundle storedResult = mResults.get(requestKey);
                if (storedResult != null) {
                    // if there is a result, fire the callback
                    listener.onFragmentResult(requestKey, storedResult);
                    // and clear the result
                    setFragmentResult(requestKey, null);
                }
            }
            if (event == Lifecycle.Event.ON_DESTROY) {
                lifecycle.removeObserver(this);
                mResultListeners.remove(requestKey);
            }
        }
    };
    lifecycle.addObserver(observer);
    mResultListeners.put(requestKey, new LifecycleAwareResultListener(lifecycle, listener));
}

以上便是这部分的源码

这里要注意一点的是 fragment result api 是基于同一 FragmentManager

总结

官方一直致力于将 fragment 的 api 变得更好用

Ian Lake 在 Fragments: Past, Present, and Future (Android Dev Summit '19) 中提到了 fragment 间通信的问题,未来 fragment 会整合 fragment 自身和其内部 view 的生命周期,提供同一 FragmentManager 多返回栈的支持

看到 fragment result API ,我突然有个想法,如果将其应用到 Navigation 中是否是解决 Navigation 跳转返回后状态重置的一个方法呢?

各位小伙伴有什么想法欢迎评论区留言

关于我

我是 Fly_with24

  • 掘金

  • 简书

  • Github

欢迎关注我的公众号

<think>好的,用户现在遇到了“Unresolved reference: registerForActivityResult”的错误。我需要先分析可能的原因。用户之前询问过ActivityResultContracts的使用方法,现在的问题应该是在实际编码时遇到了编译错误。 首先,这个错误通常发生在Kotlin或Android项目中,当编译器无法找到某个函数或类的定义时。registerForActivityResult是AndroidX中的一个方法,所以可能的原因包括依赖项未正确添加、使用的版本过旧,或者导入的包不正确。 接下来,我需要考虑用户的开发环境。用户可能在使用旧版本的Android Studio或者没有正确添加所需的依赖库。例如,如果他们的项目中没有引入androidx.activity:activity-ktx库,或者版本低于1.2.0,就会导致找不到这个方法。此外,用户可能是在Fragment中调用,但Fragment的库版本也可能影响。 然后,用户可能按照之前的指导编写了代码,但忽略了依赖项的配置。需要检查build.gradle文件中的dependencies部分,确认是否有正确的implementation语句。同时,可能还需要检查是否启用了Jetpack库,或者是否在模块级别的build.gradle中配置了正确的仓库。 另一个可能性是用户没有正确导入所需的类。例如,registerForActivityResult属于androidx.activity.result包,如果用户没有导入相关的包,编译器会找不到引用。此外,用户可能在Activity或Fragment中没有正确初始化,比如在onCreate方法之外注册launcher,或者使用了错误的作用域。 还需要考虑Kotlin扩展的问题,是否使用了正确的插件或配置。例如,activity-ktx库提供了Kotlin扩展函数,可能需要kotlin-android-extensions插件,但该插件已废弃,应改用view binding或其他方式。 此外,用户可能混淆了Activity和Fragment中的使用方式,虽然两者都支持registerForActivityResult,但需要确保在正确的上下文中调用。例如,在Fragment中注册时,可能需要使用fragment-ktx库的不同版本。 最后,可能需要建议用户清理并重建项目,或者同步Gradle文件,以确保所有依赖项正确加载。如果这些步骤都检查过了,问题可能出在IDE缓存或其他配置问题上,可以尝试Invalidate Caches / Restart。 总结起来,我需要分步骤引导用户检查依赖项版本、导入语句、项目配置,并提供具体的代码示例和解决方法,帮助他们解决编译错误。</think>当出现 **`Unresolved reference: registerForActivityResult`** 错误时,通常是因为以下原因导致编译器无法识别该API。以下是完整的排查和解决方案: --- ### 一、问题原因 1. **依赖库版本过低** `registerForActivityResult` 是 `androidx.activity:activity-ktx` 库提供的API,需确保版本 ≥ **1.2.0**。 2. **未正确导入依赖** 项目未添加 `activity-ktx` 或 `fragment-ktx` 库的依赖。 3. **Kotlin/Jetpack版本冲突** 与其他Jetpack库(如 `fragment`、`appcompat`)的版本不兼容。 --- ### 二、解决方案 #### 步骤1:检查Gradle依赖 在 **`app/build.gradle`** 中添加最版本的 `activity-ktx`: ```groovy dependencies { // 确保版本 ≥ 1.2.0 implementation "androidx.activity:activity-ktx:1.8.0" implementation "androidx.fragment:fragment-ktx:1.6.2" // 如果使用Fragment } ``` #### 步骤2:同步Gradle - 点击Android Studio右上角的 **Sync Now** - 或运行命令行:`./gradlew clean build` --- ### 三、验证代码写法 #### 正确使用场景(在Activity中): ```kotlin class MainActivity : AppCompatActivity() { // 1. 定义Launcher(通常在类顶部声明) private val launcher = registerForActivityResult( ActivityResultContracts.StartActivityForResult() ) { result -> // 处理结果 } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // 2. 启动操作 launcher.launch(Intent(this, TargetActivity::class.java)) } } ``` #### 在Fragment中: ```kotlin class MyFragment : Fragment() { private val launcher = registerForActivityResult( ActivityResultContracts.RequestPermission() ) { isGranted -> /* 处理权限结果 */ } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { launcher.launch(Manifest.permission.CAMERA) } } ``` --- ### 四、常见错误排查 | 问题现象 | 解决方案 | |---------|----------| | 仍报 `Unresolved reference` | 清理项目:**Build > Clean Project** → **Rebuild Project** | | 依赖冲突 | 统一Jetpack库版本:<br> `androidx.appcompat:appcompat` 和 `androidx.core:core-ktx` 需与 `activity-ktx` 版本兼容 | | 旧版API残留 | 替换 `startActivityForResult()` 和 `onActivityResult()` 的旧代码 | --- ### 五、版本兼容性参考 | 库名称 | 最低版本要求 | |----------------------|------------| | `androidx.activity:activity-ktx` | 1.2.0 | | `androidx.fragment:fragment-ktx` | 1.3.0 | | Kotlin版本 | ≥ 1.5.0 | --- ### 六、最终验证 1. 确保依赖已添加并同步成功 ![Gradle同步成功截图](https://via.placeholder.com/300x100/4CAF50/FFFFFF?text=Gradle+Sync+Success) 2. 确认导入语句存在 ```kotlin import androidx.activity.result.contract.ActivityResultContracts import androidx.activity.result.registerForActivityResult ``` 3. 尝试编译运行,错误应已消失。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值