日韩性视频-久久久蜜桃-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ò),歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 怎么可能高潮了就结束漫画 | 欧美极品第一页 | 国产欧美一区二区三区鸳鸯浴 | 成人日韩视频 | 国产黄a三级三级看三级 | 99久久婷婷国产综合精品青牛牛 | 强开小受嫩苞第一次免费视频 | 欧美精品久久久久久久自慰 | 午夜爱爱毛片xxxx视频免费看 | 日本成人中文字幕 | 精国产人伦一区二区三区 | 久久亚洲av无码西西人体 | 欧美高清日韩 | 思思99精品视频在线观看 | 免费视频一区 | 草久影院 | 人人看人人看 | 久久精品国产欧美亚洲人人爽 | av网址在线看| 99riAv国产精品无码鲁大师 | 女同在线视频 | 公交顶臀绿裙妇女配视频 | 最近的中文字幕 | 五月婷婷操 | 精品一区电影国产 | 国产区在线观看视频 | 欧美日韩国产一区 | 久久无码人妻丰满熟妇区毛片 | 美女精品一区 | 黑人巨大国产9丨视频 | 久久视频免费观看 | 激情在线视频 | 成人国产精品免费观看动漫 | 国产精品一区二区亚洲 | 青娱乐欧美 | a天堂资源| 黄色在线小视频 | 亚洲美女自拍偷拍 | 少妇高潮迭起 | 欧美少妇性生活 | 三级全黄视频 | 日韩精品视频一区二区三区 | 精品视频一区在线观看 | 天天插天天插 | 精品欧美日韩 | 亚洲一区激情 | 成年人看片网站 | 黄色一级片在线 | 精品人妻一区二区三区四区不卡 | 欧美成人激情在线 | 狠狠爱夜夜操 | 国产精品视频一区二区三区, | 黄色无毒网站 | 一级少妇精品久久久久久久 | 亚洲www.| 欧美精品黑人猛交高潮 | 久久久久久久久亚洲 | 国产三级按摩推拿按摩 | 久久y| 日本精品久久久 | 亚洲色偷偷综合亚洲av伊人 | 中出在线播放 | 999国产精品视频 | 日韩精品成人在线 | 伊人网在线视频观看 | 欧美大胆a视频 | 国产高清在线免费观看 | 日本少妇与黑人 | 黑人三级视频 | 国产精品久久久久久久裸模 | 欧美成年人视频在线观看 | 中文字幕亚洲高清 | 韩国一区二区三区视频 | 亚洲三级在线免费观看 | 成人精品视频 | 看黄色一级大片 | 日日夜夜一区二区 | 综合色吧 | 国产精品乱码 | 欧美激情小视频 | 91尤物国产福利在线观看 | 一边摸一边做爽的视频17国产 | 朋友人妻少妇精品系列 | 麻豆精品在线 | 锕锕锕锕锕锕锕锕 | 国语对白做受69按摩 | 亚洲va天堂va国产va久 | 亚洲精品综合精品自拍 | 网站色 | 亚洲一区二区三区四区五区六区 | 亚洲天堂五码 | 国产第六页 | 悠悠色影院| 桃色成人网| 国产日韩第一页 | 国产在线xx | 亚洲激情网| 看片网址国产福利av中文字幕 | 狠狠干免费视频 |