Fragment通過FragmentManager實(shí)現(xiàn)通信功能詳細(xì)講解
一、自己的理解
本質(zhì)就是Fragment經(jīng)由同一個(gè)FragmentManager以觀察者模式的方式通信。
首先多個(gè)Fragment通過同一個(gè)實(shí)例做到觀察者模式的通信。
其次Fragment都是由FragmentManager來管理的,F(xiàn)ragemnt的重建數(shù)據(jù)的保存等,各種機(jī)制都由FragmentManager控制,所以選擇FragmentManager來當(dāng)這個(gè)同一個(gè)實(shí)例是最合適不過。
所以一個(gè)經(jīng)由同一個(gè)FragmentManager以觀察者模式的方式通信就出現(xiàn)了。
二、使用
1.接收數(shù)據(jù)
FragmentManager.setFragmentResultListener( requestKey, lifecycleOwner, FragmentResultListener { requestKey: String, result: Bundle -> 在這里可以通過requestKey的判斷,來區(qū)別處理 })
如果想在 Fragment 中接受數(shù)據(jù),可以在 FragmentManager 中注冊一個(gè) FragmentResultListener,通過對requestKey 的判斷,區(qū)別處理 FragmentManager 發(fā)送的數(shù)據(jù)
setFragmentResultListener方法的參數(shù)中,攜帶著lifecycleOwner,它對生命周期進(jìn)行了監(jiān)聽,只有在Started狀態(tài)之后才能接收信息,并且對Started狀態(tài)之前最后一次發(fā)送的數(shù)據(jù)有黏性,即Started之前發(fā)的最后一條消息,在Started狀態(tài)之后會(huì)收到,當(dāng)lifecycleOwner生命周期到銷毀的時(shí)候會(huì)移除這個(gè)FragmentResultListener。
2.發(fā)送數(shù)據(jù)
FragmentManager.setFragmentResult( requestKey, bundleOf(key to value) )
注意事項(xiàng):
通信的Fragment要使用同一個(gè)FragmentManager來接收和發(fā)送信息。
舉例:
(1).如果在 FragmentA 中接收FragmentB 發(fā)送的數(shù)據(jù),F(xiàn)ragmentA 和 FragmentB 處于相同的層級(jí),它們的共同點(diǎn)是被上一層級(jí)的FragmentManager所控制,parentFragmentManager就是他倆的同一個(gè)實(shí)例的FragmentManager,所以他們都通過parentFragmentManager來通信。
(2).如果在 FragmentA 中接受 FragmentB 發(fā)送的數(shù)據(jù),F(xiàn)ragmentA 是 FragmentB 的父容器,那對于FragemntA來說它和FragemntB的共同的FragmentManager是A的childFragmentManager,對于FragmentB來說它和A的共同的FragmentManager是B的parentFragmentManager,所以A接收B的消息用childFragmentManager,B發(fā)送A的消息用parentFragmentManager
三、源碼分析
1.發(fā)送數(shù)據(jù)
private final ConcurrentHashMap<String, Bundle> mResults = new ConcurrentHashMap<>(); private final ConcurrentHashMap<String, LifecycleAwareResultListener> mResultListeners = new ConcurrentHashMap<>(); @Override public final void setFragmentResult(@NonNull String requestKey, @Nullable Bundle result) { if (result == null) { // mResults 是 ConcurrentHashMap 的實(shí)例,用來存儲(chǔ)數(shù)據(jù)傳輸?shù)?Bundle // 如果傳遞的參數(shù) result 為空,移除 requestKey 對應(yīng)的 Bundle mResults.remove(requestKey); return; } // Check if there is a listener waiting for a result with this key // mResultListeners 是 ConcurrentHashMap 的實(shí)例,用來儲(chǔ)存注冊的 listener // 獲取 requestKey 對應(yīng)的 listener LifecycleAwareResultListener resultListener = mResultListeners.get(requestKey); if (resultListener != null && resultListener.isAtLeast(Lifecycle.State.STARTED)) { // 如果 resultListener 不為空,并且生命周期處于 STARTED 狀態(tài)時(shí),調(diào)用回調(diào) resultListener.onFragmentResult(requestKey, result); } else { // 否則保存當(dāng)前傳輸?shù)臄?shù)據(jù) mResults.put(requestKey, result); } }
我們看到這兩個(gè)集合:
private final Map<String, Bundle> mResults = Collections.synchronizedMap(new HashMap<String, Bundle>()); private final Map<String, LifecycleAwareResultListener> mResultListeners = Collections.synchronizedMap(new HashMap<String, LifecycleAwareResultListener>());
就明白,這就是觀察者模式保存觀察者的地方,再看發(fā)送數(shù)據(jù)的方法, 果然就是通過requestKey來找到對應(yīng)的觀察者,然后調(diào)用onFragmentResult方法通知觀察者。
注意當(dāng)resultListener生命周期狀態(tài)不到Started的時(shí)候,會(huì)先把數(shù)據(jù)保存mResults.put(requestKey, result);,在監(jiān)聽到生命周期狀態(tài)到Started時(shí),會(huì)取一次數(shù)據(jù),然后這個(gè)mResults是一個(gè)map,所以只會(huì)保存最后一次put的數(shù)據(jù),所以在Started生命周期前發(fā)送的最后一次數(shù)據(jù),有黏性。
2.接收數(shù)據(jù)
private final ConcurrentHashMap<String, LifecycleAwareResultListener> mResultListeners = new ConcurrentHashMap<>(); @Override public final void setFragmentResultListener(@NonNull final String requestKey, @NonNull final LifecycleOwner lifecycleOwner, @Nullable final FragmentResultListener listener) { // mResultListeners 是 ConcurrentHashMap 的實(shí)例,用來儲(chǔ)存注冊的 listener // 如果傳遞的參數(shù) listener 為空時(shí),移除 requestKey 對應(yīng)的 listener if (listener == null) { mResultListeners.remove(requestKey); return; } // Lifecycle是一個(gè)生命周期感知組件,一般用來響應(yīng)Activity、Fragment等組件的生命周期變化 final Lifecycle lifecycle = lifecycleOwner.getLifecycle(); // 當(dāng)生命周期處于 DESTROYED 時(shí),直接返回 // 避免當(dāng) Fragment 處于不可預(yù)知狀態(tài)的時(shí),可能發(fā)生未知的問題 if (lifecycle.getCurrentState() == Lifecycle.State.DESTROYED) { return; } // 開始監(jiān)聽生命周期 LifecycleEventObserver observer = new LifecycleEventObserver() { @Override public void onStateChanged(@NonNull LifecycleOwner source, @NonNull Lifecycle.Event event) { // 當(dāng)生命周期處于 ON_START 時(shí)開始處理數(shù)據(jù) if (event == Lifecycle.Event.ON_START) { // 開始檢查受到的數(shù)據(jù) Bundle storedResult = mResults.get(requestKey); if (storedResult != null) { // 如果結(jié)果不為空,調(diào)用回調(diào)方法 listener.onFragmentResult(requestKey, storedResult); // 清除數(shù)據(jù) setFragmentResult(requestKey, null); } } // 當(dāng)生命周期處于 ON_DESTROY 時(shí),移除監(jiān)聽 if (event == Lifecycle.Event.ON_DESTROY) { lifecycle.removeObserver(this); mResultListeners.remove(requestKey); } } }; lifecycle.addObserver(observer); mResultListeners.put(requestKey, new FragmentManager.LifecycleAwareResultListener(lifecycle, listener)); }
Lifecycle是一個(gè)生命周期感知組件,一般用來響應(yīng)Activity、Fragment等組件的生命周期變化
獲取 Lifecycle 去監(jiān)聽 Fragment 的生命周期的變化
當(dāng)生命周期處于 ON_START 時(shí)開始處理數(shù)據(jù),避免當(dāng) Fragment 處于不可預(yù)知狀態(tài)的時(shí),可能發(fā)生未知的問題
當(dāng)生命周期處于 ON_DESTROY 時(shí),移除監(jiān)聽
如果大家看過我的Lifecycle源碼分析的文章,就會(huì)很簡單的看出來這就是一個(gè)簡單的觀察者模式。
四、小結(jié)
這種方式只能傳遞簡單數(shù)據(jù)類型、Serializable 和 Parcelable 數(shù)據(jù),F(xiàn)ragment result APIs 允許程序從崩潰中恢復(fù)數(shù)據(jù),而且不會(huì)持有對方的引用,避免當(dāng) Fragment 處于不可預(yù)知狀態(tài)的時(shí),可能發(fā)生未知的問題。
優(yōu)點(diǎn):
在 Fragment 之間傳遞數(shù)據(jù),不會(huì)持有對方的引用
當(dāng)生命周期處于 ON_START 時(shí)開始處理數(shù)據(jù),避免當(dāng) Fragment 處于不可預(yù)知狀態(tài)的時(shí),可能發(fā)生未知的問題
當(dāng)生命周期處于 ON_DESTROY 時(shí),移除監(jiān)聽
到此這篇關(guān)于Fragment通過FragmentManager實(shí)現(xiàn)通信功能詳細(xì)講解的文章就介紹到這了,更多相關(guān)Fragment FragmentManager通信內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Android 照相機(jī)的實(shí)例應(yīng)用
這篇文章主要介紹了Android 照相機(jī)的實(shí)例應(yīng)用的相關(guān)資料,希望通過此文能掌握Android照相機(jī)的使用方法,需要的朋友可以參考下2017-08-08android實(shí)用工具類分享(獲取內(nèi)存/檢查網(wǎng)絡(luò)/屏幕高度/手機(jī)分辨率)
這篇文章主要介紹了android實(shí)用工具類,包括獲取內(nèi)存、檢查網(wǎng)絡(luò)、屏幕高度、手機(jī)分辨率、獲取版本號(hào)等功能,需要的朋友可以參考下2014-03-03Android中ScrollView監(jiān)聽滑動(dòng)距離案例講解
這篇文章主要介紹了Android中ScrollView監(jiān)聽滑動(dòng)距離案例講解,本篇文章通過簡要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下2021-08-08Android開發(fā)實(shí)現(xiàn)的Log統(tǒng)一管理類
這篇文章主要介紹了Android開發(fā)實(shí)現(xiàn)的Log統(tǒng)一管理類,涉及Android日志管理及方法重載等相關(guān)操作技巧,需要的朋友可以參考下2017-12-12Android 實(shí)現(xiàn)圖片生成卷角和圓角縮略圖的方法
本篇文章主要介紹了Android 實(shí)現(xiàn)圖片生成卷角和圓角縮略圖的方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-11-11解決android Listview的item中最外層Margin失效的問題
下面小編就為大家?guī)硪黄鉀Qandroid Listview的item中最外層Margin失效的問題。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-04-04Android仿ViVO X6 極速閃充動(dòng)畫效果
這篇文章主要介紹了Android仿ViVO X6 極速閃充動(dòng)畫效果,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-07-07