Fragment通過FragmentManager實現(xiàn)通信功能詳細講解
一、自己的理解
本質(zhì)就是Fragment經(jīng)由同一個FragmentManager以觀察者模式的方式通信。
首先多個Fragment通過同一個實例做到觀察者模式的通信。
其次Fragment都是由FragmentManager來管理的,F(xiàn)ragemnt的重建數(shù)據(jù)的保存等,各種機制都由FragmentManager控制,所以選擇FragmentManager來當(dāng)這個同一個實例是最合適不過。
所以一個經(jīng)由同一個FragmentManager以觀察者模式的方式通信就出現(xiàn)了。
二、使用
1.接收數(shù)據(jù)
FragmentManager.setFragmentResultListener(
requestKey,
lifecycleOwner,
FragmentResultListener { requestKey: String, result: Bundle ->
在這里可以通過requestKey的判斷,來區(qū)別處理
})
如果想在 Fragment 中接受數(shù)據(jù),可以在 FragmentManager 中注冊一個 FragmentResultListener,通過對requestKey 的判斷,區(qū)別處理 FragmentManager 發(fā)送的數(shù)據(jù)
setFragmentResultListener方法的參數(shù)中,攜帶著lifecycleOwner,它對生命周期進行了監(jiān)聽,只有在Started狀態(tài)之后才能接收信息,并且對Started狀態(tài)之前最后一次發(fā)送的數(shù)據(jù)有黏性,即Started之前發(fā)的最后一條消息,在Started狀態(tài)之后會收到,當(dāng)lifecycleOwner生命周期到銷毀的時候會移除這個FragmentResultListener。
2.發(fā)送數(shù)據(jù)
FragmentManager.setFragmentResult(
requestKey,
bundleOf(key to value)
)
注意事項:
通信的Fragment要使用同一個FragmentManager來接收和發(fā)送信息。
舉例:
(1).如果在 FragmentA 中接收FragmentB 發(fā)送的數(shù)據(jù),F(xiàn)ragmentA 和 FragmentB 處于相同的層級,它們的共同點是被上一層級的FragmentManager所控制,parentFragmentManager就是他倆的同一個實例的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ù)據(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 的實例,用來儲存注冊的 listener
// 獲取 requestKey 對應(yīng)的 listener
LifecycleAwareResultListener resultListener = mResultListeners.get(requestKey);
if (resultListener != null && resultListener.isAtLeast(Lifecycle.State.STARTED)) {
// 如果 resultListener 不為空,并且生命周期處于 STARTED 狀態(tài)時,調(diào)用回調(diào)
resultListener.onFragmentResult(requestKey, result);
} else {
// 否則保存當(dāng)前傳輸?shù)臄?shù)據(jù)
mResults.put(requestKey, result);
}
}我們看到這兩個集合:
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ù)據(jù)保存mResults.put(requestKey, result);,在監(jiān)聽到生命周期狀態(tài)到Started時,會取一次數(shù)據(jù),然后這個mResults是一個map,所以只會保存最后一次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 的實例,用來儲存注冊的 listener
// 如果傳遞的參數(shù) listener 為空時,移除 requestKey 對應(yīng)的 listener
if (listener == null) {
mResultListeners.remove(requestKey);
return;
}
// Lifecycle是一個生命周期感知組件,一般用來響應(yīng)Activity、Fragment等組件的生命周期變化
final Lifecycle lifecycle = lifecycleOwner.getLifecycle();
// 當(dāng)生命周期處于 DESTROYED 時,直接返回
// 避免當(dāng) Fragment 處于不可預(yù)知狀態(tài)的時,可能發(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ù)據(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 時,移除監(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是一個生命周期感知組件,一般用來響應(yīng)Activity、Fragment等組件的生命周期變化
獲取 Lifecycle 去監(jiān)聽 Fragment 的生命周期的變化
當(dāng)生命周期處于 ON_START 時開始處理數(shù)據(jù),避免當(dāng) Fragment 處于不可預(yù)知狀態(tài)的時,可能發(fā)生未知的問題
當(dāng)生命周期處于 ON_DESTROY 時,移除監(jiān)聽
如果大家看過我的Lifecycle源碼分析的文章,就會很簡單的看出來這就是一個簡單的觀察者模式。
四、小結(jié)
這種方式只能傳遞簡單數(shù)據(jù)類型、Serializable 和 Parcelable 數(shù)據(jù),F(xiàn)ragment result APIs 允許程序從崩潰中恢復(fù)數(shù)據(jù),而且不會持有對方的引用,避免當(dāng) Fragment 處于不可預(yù)知狀態(tài)的時,可能發(fā)生未知的問題。
優(yōu)點:
在 Fragment 之間傳遞數(shù)據(jù),不會持有對方的引用
當(dāng)生命周期處于 ON_START 時開始處理數(shù)據(jù),避免當(dāng) Fragment 處于不可預(yù)知狀態(tài)的時,可能發(fā)生未知的問題
當(dāng)生命周期處于 ON_DESTROY 時,移除監(jiān)聽
到此這篇關(guān)于Fragment通過FragmentManager實現(xiàn)通信功能詳細講解的文章就介紹到這了,更多相關(guān)Fragment FragmentManager通信內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
圖解Windows環(huán)境下Android Studio安裝和使用教程
這篇文章主要介紹了圖解Windows環(huán)境下Android Studio安裝和使用教程的相關(guān)資料,需要的朋友可以參考下2015-12-12
Android DatePicker和DatePickerDialog基本用法示例
這篇文章主要介紹了Android DatePicker和DatePickerDialog基本用法,實例分析了DatePicker和DatePickerDialog控件針對手機時間設(shè)置的相關(guān)技巧,需要的朋友可以參考下2016-06-06
Android ViewDragHelper實現(xiàn)京東、淘寶拖拽詳情功能的實現(xiàn)
這篇文章主要介紹了Android ViewDragHelper實現(xiàn)京東、淘寶拖拽詳情,實現(xiàn)這種效果大概分為三種方式,具體哪三種方式大家通過本文了解下吧2018-04-04
使用Retrofit下載文件并實現(xiàn)進度監(jiān)聽的示例
這篇文章主要介紹了使用Retrofit下載文件并實現(xiàn)進度監(jiān)聽的示例,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-08-08
Android 類似UC瀏覽器的效果:向上滑動地址欄隱藏功能
這篇文章主要介紹了Android 類似UC瀏覽器的效果:向上滑動地址欄隱藏功能,需要的朋友可以參考下2017-12-12
Android開發(fā)教程之獲取系統(tǒng)輸入法高度的正確姿勢
這篇文章主要給大家介紹了關(guān)于Android開發(fā)教程之獲取系統(tǒng)輸入法高度的正確姿勢,文中通過示例代碼介紹的非常詳細,對大家學(xué)習(xí)或者使用Android具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2018-10-10

