日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

activity 点击后传递数据给fragment_Fragment 新特性 : Fragment Result API 使用以及源码分析

發(fā)布時(shí)間:2023/12/10 编程问答 18 豆豆
生活随笔 收集整理的這篇文章主要介紹了 activity 点击后传递数据给fragment_Fragment 新特性 : Fragment Result API 使用以及源码分析 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

  • 原標(biāo)題: Android Fragments: Fragment Result
  • 原文地址: https://proandroiddev.com/android-fragments-fragment-result......
  • 原文作者: Husayn Hakeem

今年 Google 推出了 Fragment Result API 和 Activity Results API,用來(lái)取代之前的 Activity 和 Fragment 之間通信方式的不足。

這篇文章大概是我在 5 月份的寫的,主要介紹 Fragment Result API,分為 譯文 和 譯者的思考 兩個(gè)部分。

Fragment Result API 主要介紹 Fragment 間通信的新方式,是在 Fragment 1.3.0-alpha04 新增加的 API ,而現(xiàn)在最新版本已經(jīng)到 fragment-1.3.0-beta01 應(yīng)該很快就能應(yīng)用在項(xiàng)目里面了。

接下來(lái)分析一下 Fragment Result API 主要為我們解決了什么問題,它都有那些更新。

通過(guò)這篇文章你將學(xué)習(xí)到以下內(nèi)容,將在譯者思考部分會(huì)給出相應(yīng)的答案

  • 新 Fragment 間通信的方式的使用?
  • 新 Fragment 間通信的源碼分析?
  • 匯總 Fragment 之間的通信的方式?

譯文

Frrgament 間傳遞數(shù)據(jù)可以通過(guò)多種方式,包括使用 target Fragment APIs (Fragment.setTargetFragment() 和 Fragment.getTargetFragment()),ViewModel 或者 使用 Fragments’ 父容器 Activity,target Fragment APIs 已經(jīng)過(guò)時(shí)了,現(xiàn)在鼓勵(lì)使用新的 Fragment result APIs 完成 Frrgament 之間傳遞數(shù)據(jù),其中傳遞數(shù)據(jù)由 FragmentManager 處理,并且在 Fragments 設(shè)置發(fā)送數(shù)據(jù)和接受數(shù)據(jù)

在 Frrgament 之間傳遞數(shù)據(jù)

使用新的 Fragment APIs 在 兩個(gè) Frrgament 之間的傳遞,沒有任何引用,可以使用它們公共的 FragmentManager,它充當(dāng) Frrgament 之間傳遞數(shù)據(jù)的中心存儲(chǔ)。

接受數(shù)據(jù)

如果想在 Fragment 中接受數(shù)據(jù),可以在 FragmentManager 中注冊(cè)一個(gè) FragmentResultListener,參數(shù) requestKey 可以過(guò)濾掉 FragmentManager 發(fā)送的數(shù)據(jù)

FragmentManager.setFragmentResultListener(requestKey,lifecycleOwner,FragmentResultListener { requestKey: String, result: Bundle ->// Handle result})

參數(shù) lifecycleOwner 可以觀察生命周期,當(dāng) Fragment 的生命周期處于 STARTED 時(shí)接受數(shù)據(jù)。如果監(jiān)聽 Fragment 的生命周期,您可以在接收到新數(shù)據(jù)時(shí)安全地更新 UI,因?yàn)?view 的創(chuàng)建(onViewCreated() 方法在 onStart() 之前被調(diào)用)。

當(dāng)生命周期處于 LifecycleOwner STARTED 的狀態(tài)之前,如果有多個(gè)數(shù)據(jù)傳遞,只會(huì)接收到最新的值

當(dāng)生命周期處于 LifecycleOwner DESTROYED 時(shí),它將自動(dòng)移除 listener,如果想手動(dòng)移除 listener,需要調(diào)用 FragmentManager.setFragmentResultListener() 方法,傳遞空的 FragmentResultListener

在 FragmentManager 中注冊(cè) listener,依賴于 Fragment 發(fā)送返回的數(shù)據(jù)

  • 如果在 FragmentA 中接受 FragmentB 發(fā)送的數(shù)據(jù),FragmentA 和 FragmentB 處于相同的層級(jí),通過(guò) parent FragmentManager 進(jìn)行通信,FragmentA 必須使用 parent FragmentManager 注冊(cè) listener
parentFragmentManager.setFragmentResultListener(...)
  • 如果在 FragmentA 中接受 FragmentB 發(fā)送的數(shù)據(jù),FragmentA 是 FragmentB 的父容器, 他們通過(guò) child FragmentManager 進(jìn)行通信
childFragmentManager.setFragmentResultListener(...)

listener 必須設(shè)置的Fragment 相同的 FragmentManager

發(fā)送數(shù)據(jù)

如果 FragmentB 發(fā)送數(shù)據(jù)給 FragmentA,需要在 FragmentA 中注冊(cè) listener,通過(guò) parent FragmentManager 發(fā)送數(shù)據(jù)

parentFragmentManager.setFragmentResult(requestKey, // Same request key FragmentA used to register its listenerbundleOf(key to value) // The data to be passed to FragmentA )

測(cè)試 Fragment Results

測(cè)試 Fragment 是否成功接收或發(fā)送數(shù)據(jù),可以使用 FragmentScenario API

接受數(shù)據(jù)

如果在 FragmentA 中注冊(cè) FragmentResultListener 接受數(shù)據(jù),你可以模擬 parent FragmentManager 發(fā)送數(shù)據(jù),如果在 FragmentA 中正確注冊(cè)了 listener,可以用來(lái)驗(yàn)證 FragmentA 是否能收到數(shù)據(jù),例如,如果在 FragmentA 中接受數(shù)據(jù)并更新 UI, 可以使用 Espresso APIs 來(lái)驗(yàn)證是否期望的數(shù)據(jù)

@Test fun shouldReceiveData() {val scenario = FragmentScenario.launchInContainer(FragmentA::class.java)// Pass data using the parent fragment managerscenario.onFragment { fragment ->val data = bundleOf(KEY_DATA to "value")fragment.parentFragmentManager.setFragmentResult("aKey", data)}// Verify data is received, for example, by verifying it's been displayed on the UIonView(withId(R.id.textView)).check(matches(withText("value"))) }

發(fā)送數(shù)據(jù)

可以在 FragmentB 的 parent FragmentManager 上注冊(cè)一個(gè) FragmentResultListener 來(lái)測(cè)試 FragmentB 是否成功發(fā)送數(shù)據(jù),當(dāng)發(fā)送數(shù)據(jù)結(jié)束時(shí),可以來(lái)驗(yàn)證這個(gè) listener 是否能收到數(shù)據(jù)

@Test fun shouldSendData() {val scenario = FragmentScenario.launchInContainer(FragmentB::class.java)// Register result listenervar receivedData = ""scenario.onFragment { fragment ->fragment.parentFragmentManager.setFragmentResultListener(KEY,fragment,FragmentResultListener { key, result ->receivedData = result.getString(KEY_DATA)})}// Send dataonView(withId(R.id.send_data)).perform(click())// Verify data was successfully sentassertThat(receivedData).isEqualTo("value") }

總結(jié)

雖然使用了 Fragment result APIs,替換了過(guò)時(shí)的 Fragment target APIs,但是新的 APIs 在Bundle 作為數(shù)據(jù)傳傳遞方面有一些限制,只能傳遞簡(jiǎn)單數(shù)據(jù)類型、Serializable 和 Parcelable 數(shù)據(jù),Fragment result APIs 允許程序從崩潰中恢復(fù)數(shù)據(jù),而且不會(huì)持有對(duì)方的引用,避免當(dāng) Fragment 處于不可預(yù)知狀態(tài)的時(shí),可能發(fā)生未知的問題

譯者的思考

這是譯者的一些思考,總結(jié)一下 Fragment 1.3.0-alpha04 新增加的 Fragment 間通信的 API

數(shù)據(jù)接受

FragmentManager.setFragmentResultListener(requestKey,lifecycleOwner,FragmentResultListener { requestKey: String, result: Bundle ->// Handle result})

數(shù)據(jù)發(fā)送

parentFragmentManager.setFragmentResult(requestKey, // Same request key FragmentA used to register its listenerbundleOf(key to value) // The data to be passed to FragmentA )

那么 Fragment 間通信的新 API 給我們帶來(lái)哪些好處呢:

  • 在 Fragment 之間傳遞數(shù)據(jù),不會(huì)持有對(duì)方的引用
  • 當(dāng)生命周期處于 ON_START 時(shí)開始處理數(shù)據(jù),避免當(dāng) Fragment 處于不可預(yù)知狀態(tài)的時(shí),可能發(fā)生未知的問題
  • 當(dāng)生命周期處于 ON_DESTROY 時(shí),移除監(jiān)聽

我們一起來(lái)從源碼的角度分析一下 Google 是如何做的

源碼分析

按照慣例從調(diào)用的方法來(lái)分析,數(shù)據(jù)接受時(shí),調(diào)用了 FragmentManager 的 setFragmentResultListener 方法

androidx.fragment/fragment/1.3.0-alpha04......androidx/fragment/app/FragmentManager.java

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í)例,用來(lái)儲(chǔ)存注冊(cè)的 listener// 如果傳遞的參數(shù) listener 為空時(shí),移除 requestKey 對(duì)應(yīng)的 listenerif (listener == null) {mResultListeners.remove(requestKey);return;}// Lifecycle是一個(gè)生命周期感知組件,一般用來(lái)響應(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() {@Overridepublic 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è)生命周期感知組件,一般用來(lái)響應(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)聽

接下來(lái)一起來(lái)看一下數(shù)據(jù)發(fā)送的方法,調(diào)用了 FragmentManager 的 setFragmentResult 方法

androidx.fragment/fragment/1.3.0-alpha04......androidx/fragment/app/FragmentManager.java

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í)例,用來(lái)存儲(chǔ)數(shù)據(jù)傳輸?shù)?Bundle// 如果傳遞的參數(shù) result 為空,移除 requestKey 對(duì)應(yīng)的 BundlemResults.remove(requestKey);return;}// mResultListeners 是 ConcurrentHashMap 的實(shí)例,用來(lái)儲(chǔ)存注冊(cè)的 listener// 獲取 requestKey 對(duì)應(yīng)的 listenerLifecycleAwareResultListener 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);} }
  • 獲取 requestKey 注冊(cè)的 listener
  • 當(dāng)生命周期處于 STARTED 狀態(tài)時(shí),開始發(fā)送數(shù)據(jù)
  • 否則保存當(dāng)前傳輸?shù)臄?shù)據(jù)

源碼分析到這里結(jié)束了,我們一起來(lái)思考一下,在之前我們的都有那些數(shù)據(jù)傳方式

匯總 Fragment 之間的通信的方式

  • 通過(guò)共享 ViewModel 或者關(guān)聯(lián) Activity來(lái)完成,Fragment 之間不應(yīng)該直接通信 參考 Google: ViewModel#sharing
  • 通過(guò)接口,可以在 Fragment 定義接口,并在 Activity 實(shí)現(xiàn)它 參考 Google: 與其他 Fragment 通信
  • 通過(guò)使用 findFragmentById 方法,獲取 Fragment 的實(shí)例,然后調(diào)用 Fragment 的公共方法 參考 Google: 與其他 Fragment 通信
  • 調(diào)用 Fragment.setTargetFragment() 和 Fragment.getTargetFragment() 方法,但是注意 target fragment 需要直接訪問另一個(gè) fragment 的實(shí)例,這是十分危險(xiǎn)的,因?yàn)槟悴恢滥繕?biāo) fragment 處于什么狀態(tài)
  • Fragment 新的 API, setFragmentResult() 和 setFragmentResultListener()

綜合以上通信方式,那么你認(rèn)為 Fragment 之間通信最好的方式是什么?

參考文獻(xiàn)

  • Now in Android #17: https://medium.com/androiddeve......
  • Pass data between fragments: https://developer.android.com/training/basi......
  • ViewModel#sharing: https://developer.android.com/topic/librari......
  • 與其他 Fragment 通信: https://developer.android.com/training/basic......

結(jié)語(yǔ)

全文到這里就結(jié)束了,如果有幫助 點(diǎn)個(gè)贊 就是對(duì)我最大的鼓勵(lì)!

致力于分享一系列 Android 系統(tǒng)源碼、逆向分析、算法、翻譯、Jetpack 源碼相關(guān)的文章,在技術(shù)的道路上一起前進(jìn)


最后推薦我一直在更新維護(hù)的項(xiàng)目和網(wǎng)站:

  • 計(jì)劃建立一個(gè)最全、最新的 AndroidX Jetpack 相關(guān)組件的實(shí)戰(zhàn)項(xiàng)目 以及 相關(guān)組件原理分析文章,正在逐漸增加 Jetpack 新成員,倉(cāng)庫(kù)持續(xù)更新,歡迎前去查看:
AndroidX-Jetpack-Practice?github.com
  • LeetCode / 劍指 offer / 國(guó)內(nèi)外大廠面試題 / 多線程 題解,語(yǔ)言 Java 和 kotlin,包含多種解法、解題思路、時(shí)間復(fù)雜度、空間復(fù)雜度分析

    • 劍指 offer 及國(guó)內(nèi)外大廠面試題解:
劍指Offer題解?offer.hi-dhl.com
    • LeetCode 系列題解:
LeetCode 系列題解?leetcode.hi-dhl.com
  • 最新 Android 10 源碼分析系列文章,了解系統(tǒng)源碼,不僅有助于分析問題,在面試過(guò)程中,對(duì)我們也是非常有幫助的,倉(cāng)庫(kù)持續(xù)更新,歡迎前去查看
hi-dhl/Android10-Source-Analysis?github.com
  • 整理和翻譯一系列精選國(guó)外的技術(shù)文章,每篇文章都會(huì)有譯者思考部分,對(duì)原文的更加深入的解讀,倉(cāng)庫(kù)持續(xù)更新,歡迎前去查看
hi-dhl/Technical-Article-Translation?github.com
  • 「為互聯(lián)網(wǎng)人而設(shè)計(jì),國(guó)內(nèi)國(guó)外名站導(dǎo)航」涵括新聞、體育、生活、娛樂、設(shè)計(jì)、產(chǎn)品、運(yùn)營(yíng)、前端開發(fā)、Android 開發(fā)等等網(wǎng)址,歡迎前去查看
Hi World | 為互聯(lián)網(wǎng)人而設(shè)計(jì)的國(guó)內(nèi)國(guó)外名站導(dǎo)航?site.51git.cn

總結(jié)

以上是生活随笔為你收集整理的activity 点击后传递数据给fragment_Fragment 新特性 : Fragment Result API 使用以及源码分析的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 人人爽夜夜爽 | 93久久精品日日躁夜夜躁欧美 | 中文字幕成人在线 | 国产东北女人做受av | 精品免费国产 | www国产在线观看 | 国产精品永久久久久久久久久 | 久久精品2019中文字幕 | 一本色道久久综合亚洲精品按摩 | 秋霞av在线 | 午夜免费福利视频 | 成人欧美一区二区三区黑人孕妇 | 人人妻人人澡人人爽人人dvd | 色呦呦国产 | 久久久久久久国产视频 | 亚洲国产精品影院 | 国产精品久久久久久久久夜色 | 国产精品久久久国产盗摄 | 日本视频网站在线观看 | 免费在线观看av网站 | 欧美一区二区免费 | 久久老熟女一区二区三区 | 欧美一区二区三区黄片 | 色骚网 | 理论片午午伦夜理片影院99 | 国产情侣久久久久aⅴ免费 caoporn成人 | 一区二区三区色 | 未满十八岁禁止进入 | 中文字幕欧美人妻精品一区蜜臀 | 成年人网站免费在线观看 | 青青操91 | 国产在线视频网 | 国产成人精品亚洲男人的天堂 | 国产自产视频 | h视频网站在线观看 | 免费在线看黄的网站 | 超碰狠狠干 | 一级黄av | 国产乱人乱偷精品视频a人人澡 | 国产不卡视频在线播放 | 美女午夜视频 | 国产黄色片免费在线观看 | 精品无码一区二区三区蜜臀 | 亚洲高清色 | 中文字幕精品在线 | 欧美日韩国产精品一区二区三区 | 3级av | 午夜高清福利 | 精品久久久久一区二区 | 国产手机在线观看 | 日本暧暧视频 | 91插插插插插插插 | 激情五月色综合国产精品 | 最新天堂在线视频 | 国产免费视频一区二区三区 | 色综合啪啪 | 一区二区三区视频在线免费观看 | 69xxxx国产| 国产午夜小视频 | 久久九九国产精品 | 日韩国产小视频 | 蜜臀尤物一区二区三区直播 | 农村老女人av | 麻豆国产尤物av尤物在线观看 | 午夜激情影视 | 国产绿帽刺激高潮对白 | 欧美乱妇一区二区三区 | 亚洲AV无码国产精品国产剧情 | 黄色片在线免费看 | 久久久久久久久久99精品 | 伊人手机在线视频 | 黄色xxx| 阿v天堂2017 欧美小视频在线观看 | 岛国av中文字幕 | 91精品国产91久久久久福利 | 国产午夜大片 | 青娱乐国产在线 | 国产喷水吹潮视频www | 啪啪网站视频 | 欧美午夜在线视频 | 叶全真三级 | 永久免费黄色 | 免费av不卡在线观看 | 国产成人无码aa精品一区 | 亚洲乱熟女一区二区三区小说 | 在线播放的av | 欧美黑人疯狂性受xxxxx喷水 | 少妇高潮毛片色欲ava片 | 欧美视频福利 | 国产免费福利 | 亚洲欧美一二三区 | 鲁在线视频 | 国产一区二区网站 | 国产精品偷伦视频免费观看了 | 亚洲日本国产 | 粉嫩av渣男av蜜乳av | 亚洲国产av一区二区三区 | 在线观看成人 | 免费高清视频一区二区三区 |