全新的Fragment通信方式

如果在 FragmentA 中接受 FragmentB 发送的数据,FragmentA 是 FragmentB 的父容器, 他们通过 child FragmentManager 进行通信

childFragmentManager.setFragmentResultListener(…)

注意 listener必须设置的Fragment需要用到相同的FragmentManager。

相同层级的两个Fragment数据传递

如果在 FragmentA 中接受 FragmentB 发送的数据,FragmentA 和 FragmentB 处于相同的层级,通过 parent FragmentManager 进行通信,FragmentA 必须使用 parent FragmentManager 注册 listener

parentFragmentManager.setFragmentResultListener(…)

源码解析


不同于之前旧的Target Fragment Api,可以看到这里将监听器和fragment的lifecycle进行绑定,这样将带来以下优点:

  • 在 Fragment 之间传递数据,不会持有对方的引用

  • 当生命周期处于 ON_START 时开始处理数据,避免当 Fragment 处于不可预知状态的时,可能发生未知的问题

  • 当生命周期处于 ON_DESTROY 时,移除监听

那让我们更进一步看下,fragment和它的lifecycle是如何进行数据监听的绑定和解绑的呢:

@Override

public final void setFragmentResultListener(@NonNull final String requestKey,

@NonNull final LifecycleOwner lifecycleOwner,

@NonNull final FragmentResultListener listener) {

final Lifecycle lifecycle = lifecycleOwner.getLifecycle();

//destroyed则直接返回

if (lifecycle.getCurrentState() == Lifecycle.State.DESTROYED) {

return;

}

LifecycleEventObserver observer = new LifecycleEventObserver() {

@Override

public void onStateChanged(@NonNull LifecycleOwner source,

@NonNull Lifecycle.Event event) {

//在start的时候进行方法调用

if (event == Lifecycle.Event.ON_START) {

// 一旦出于start状态,检查任何存储结果

Bundle storedResult = mResults.get(requestKey);

if (storedResult != null) {

// 如果查询的结果不为空,则触发回调

listener.onFragmentResult(requestKey, storedResult);

// 清除结果

clearFragmentResult(requestKey);

}

}

//destroy则移除监听

if (event == Lifecycle.Event.ON_DESTROY) {

lifecycle.removeObserver(this);

mResultListeners.remove(requestKey);

}

}

};

可以看到上面代码做了:

  • 获取 Lifecycle 去监听 Fragment 的生命周期的变化

  • 当生命周期处于 ON_START 时开始处理数据,避免当 Fragment 处于不可预知状态的时,可能发生未知的问题

  • 当生命周期处于 ON_DESTROY 时,移除监听

  • 当生命周期处于 DESTROYED 则直接返回不作处理

看过接受数据如何做的,下面再看下如何发送数据的:

@Override

public final void setFragmentResult(@NonNull String requestKey, @NonNull Bundle result) {

// 检查是否有监听器去监听requestkey结果

FragmentManager.LifecycleAwareResultListener resultListener = mResultListeners.get(requestKey);

// 如果生命周期started,则触发回调

if (resultListener != null && resultListener.isAtLeast(Lifecycle.State.STARTED)) {

resultListener.onFragmentResult(requestKey, result);

} else {

//否则 保存当前传输数据result

mResults.put(requestKey, result);

}

}

  • 获取 requestKey 注册的 listener

  • 当生命周期处于 STARTED 状态时,开始发送数据

  • 否则保存当前传输的数据

看完源码简单分享,那么再来看下fragment间通信还有哪些其他方法?

Fragment中的通信方式还有哪些

==================

通过使用findFragmentById或关联Activity获取Fragment的实例,然后调用Fragment的公共方法:


  • 第一步在被调用的MainFragment注册公共方法

//MainFragment.java文件中

public void setData(List dataList) {

adapter.set(dataList);

}

  • 第二步 在主动调用的Fragment中关联activity并获取到MainFragment后,调用公共方法

//MenuFragment.java文件中

lv.setOnItemClickListener(new AdapterView.OnItemClickListener() {

@Override

public void onItemClick(AdapterView<?> parent, View view, int position, long id) {

MainFragment mainFragment =

(MainFragment) getActivity()

.getSupportFragmentManager()

.findFragmentByTag(“mainFragment”);

mainFragment.setData(mDataList.get(position));

}

});

  • 缺点: Fragment 之间不应该直接通信 参考

developer.android.com/topic/libra…

接口回调的方式进行fragment间数据传递:


  • step1: 在Menuragment中创建一个接口以及接口对应的set方法:

//MainFragment.java文件中

public interface OnDataTransferListener {

public void dataTransfer(List dataList);

}

public void setOnDataTransferListener(OnDataTransferListener mListener) {

this.mListener = mListener;

}

  • step2: 在MenuFragment中的ListView条目点击事件中进行接口进行接口回调

//MenuFragment.java文件中

lv.setOnItemClickListener(new AdapterView.OnItemClickListener() {

@Override

public void onItemClick(AdapterView<?> parent, View view, int position, long id) {

if (mListener != null) {

mListener.dataTransfer(mDataList.get(position));

}

}

});

  • step3: 在MainActivity中根据menuFragment获取到接口的set方法,在这个方法中进行进行数据传递,具体如下:

//在MainActivity中

menuFragment.setOnDataTransferListener(new MenuFragment.OnDataTransferListener() {

@Override

public void dataTransfer(List data) {

mainFragment.setData(data);

}

});

  • 缺点: 相对Result API更复杂,具体可以参考官方文档

developer.android.com/training/ba…

通过Target Fragment APIs (Fragment.setTargetFragment() & Fragment.getTargetFragment())方法进行Fragment间数据传递:


援引Google官方的说明:

Fragment.setTargetFragment()

Use case = 2 fragments hosted by the same activity.

Where startActivityForResult() establishes a relationship between 2 activities, setTargetFragment() defines the caller/called relationship between 2 fragments.

setTargetFragment(target) lets the “called” fragment know where to send the result. onActivityResult() is called manually in this case.

通过下面的伪代码可以表示出调用关系:

public class Caller extends Fragment

Fragment called = Called.newInstance()

called.setTargetFragment(this)

public class Called extends DialogFragment

intent = amazingData

getTargetFragment().onActivityResult( getTargetRequestCode(),intent )

简而言之,假设Fragment A 跳转B 在B中做一些操作之后,想把这些操作回传给A Fragment中存在startActivityForResult()以及onActivityResult()方法,但没有setResult()方法,用于设置返回的intent,这样我们就需要通过调用getActivity().setResult(ListTitleFragment.REQUEST_DETAIL, intent);

这种方法无形当中增加了两个Fragment 与 Activity的耦合度 所以,就有了setTargetFragment()方法 在启动B的时候,可以调用 B.setTargetFragment(A,int t) 将AB关联起来, 然后在B的代码中调用 getTargetFragment().onActivityResult()将数据回传给 A

  • 缺点: 该方法目前已经被谷歌官方所废弃,Target fragment 需要直接访问另一个fragment 的实例,这是十分危险的,因为不知道目标fragment处于什么状态;

通过ViewModel容器进行Fragment间数据传递:


Activity 中的两个或更多 Fragment 需要相互通信是一种很常见的现象。想象一下拆分视图 (list-detail) Fragment 的常见情况,假设您有一个 Fragment,在该 Fragment 中,用户从列表中选择一项,还有另一个 Fragment,用于显示选定项的内容。这种情况不太容易处理,因为这两个 Fragment 都需要定义某种接口描述,并且所有者 Activity 必须将两者绑定在一起。此外,这两个 Fragment 都必须处理另一个 Fragment 尚未创建或不可见的情况。

可以使用 ViewModel 对象解决这一常见的难点。这两个 fragment 可以使用其 activity 范围共享 ViewModel 来处理此类通信,如以下示例代码所示:

public class SharedViewModel extends ViewModel {

private final MutableLiveData selected = new MutableLiveData();

public void select(Item item) {

selected.setValue(item);

}

最后

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助

因此我收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点!不论你是刚入门Android开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门

如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
家的负担。**

[外链图片转存中…(img-YdcAynwR-1715849487008)]

[外链图片转存中…(img-dxeu9VKk-1715849487011)]

[外链图片转存中…(img-0FPyqz4G-1715849487012)]

[外链图片转存中…(img-tUSVecFi-1715849487014)]

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点!不论你是刚入门Android开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门

如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值