chinese直男口爆体育生外卖, 99久久er热在这里只有精品99, 又色又爽又黄18禁美女裸身无遮挡, gogogo高清免费观看日本电视,私密按摩师高清版在线,人妻视频毛茸茸,91论坛 兴趣闲谈,欧美 亚洲 精品 8区,国产精品久久久久精品免费

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內(nèi)不再提示

Navigation源碼解析

電子工程師 ? 來源:Android開發(fā)之旅 ? 作者:四爺 ? 2021-06-15 16:38 ? 次閱讀
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

Navigation源碼解析

谷歌推出Navigation主要是為了統(tǒng)一應用內(nèi)頁面跳轉行為。本文主要是根據(jù)Navigation版本為2.1.0 的源碼進行講解。

androidx.navigation2.1.0’ ‘a(chǎn)ndroidx.navigation2.1.0’ ‘a(chǎn)ndroidx.navigation2.1.0’ ‘a(chǎn)ndroidx.navigation2.1.0’

Navigation的使用很簡單,在創(chuàng)建新項目的時候可以直接選擇 Bottom Navigation Activity 項目,這樣默認就已經(jīng)幫我們實現(xiàn)了相關頁面邏輯。

Navigation的源碼也很簡單,但是卻涉及到很多的類,主要有以下幾個:

Navigation提供查找NavController方法

NavHostFragment用于承載導航的內(nèi)容的容器

NavController通過navigate實現(xiàn)頁面的跳轉

Navigator是一個abstract,有四個主要實現(xiàn)類

NavDestination導航節(jié)點

NavGraph導航節(jié)點頁面集合

我們首先從NavHostFragment入手查看,因為他是直接定義在我們的XML文件中的,我們直接查看器生命周期方法 onCreate :

@CallSuper @Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); final Context context = requireContext();

mNavController = new NavHostController(context); //1 mNavController.setLifecycleOwner(this);

。。.。

onCreateNavController(mNavController);//2

。。.。 }

注釋1處 直接創(chuàng)建了NavHostController 并通過 findNavController 方法暴露給外部調(diào)用者。NavHostController是繼承自NavController的。注釋2處代碼如下:

@CallSuper protected void onCreateNavController(@NonNull NavController navController) { navController.getNavigatorProvider().addNavigator( new DialogFragmentNavigator(requireContext(), getChildFragmentManager())); navController.getNavigatorProvider().addNavigator(createFragmentNavigator()); }

通過navController獲取NavigatorProvider并向其中添加了兩個Navigator,分別為DialogFragmentNavigator和FragmentNavigator。另外在NavController的構造方法中還添加了另外兩個Navigator,如下:

public NavController(@NonNull Context context) { 。。.。 mNavigatorProvider.addNavigator(new NavGraphNavigator(mNavigatorProvider)); mNavigatorProvider.addNavigator(new ActivityNavigator(mContext));}

他們都是Navigator的實現(xiàn)類。分別對應于DialogFragment、Fragment和Activity的頁面跳轉。大家可能對于NavGraphNavigator一些好奇,它是用在什么地方的呢?其實我們在XML中配置的navGraph對應的navigation跟節(jié)點文件中的 startDestination 就是通過NavGraphNavigator來實現(xiàn)跳轉的。這也是它目前唯一的用途。

各個Navigator通過復寫 navigate 方法來實現(xiàn)各自的跳轉邏輯。這里重點強調(diào)下 FragmentNavigator 的實現(xiàn)邏輯:

public NavDestination navigate(@NonNull Destination destination, @Nullable Bundle args, @Nullable NavOptions navOptions, @Nullable Navigator.Extras navigatorExtras) {

。。.。

final Fragment frag = instantiateFragment(mContext, mFragmentManager, className, args); frag.setArguments(args); final FragmentTransaction ft = mFragmentManager.beginTransaction();

。。.。

ft.replace(mContainerId, frag); //1

。。.。}

最關鍵的一行代碼就是注釋1 處。他是通過 replace 來加載 Fragment 的 ,這不符合我們實際的開發(fā)邏輯。文章后續(xù)會講解如何自定義 FragmentNavigator 來避免 Fragment 在切換的時候 生命周期的執(zhí)行。

回到上文中的 navController 獲取的 NavigatorProvider 其內(nèi)部是維護了一個HashMap來存儲相關的Navigator信息。通過獲取到Navigator的注解 Name 為key 和 Navigator 的 getClass為 value 進行存儲。

我們在回到上文中的 onCreate 方法:

@CallSuper@Overridepublic void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); final Context context = requireContext();

。。.。

if (mGraphId != 0) { mNavController.setGraph(mGraphId); } else {

。。.。

if (graphId != 0) { mNavController.setGraph(graphId, startDestinationArgs); } }}

這里通過 mNavController 調(diào)用了 setGraph 。這里主要是為了解析我們的 XML 中配置的mobile_navigation節(jié)點信息文件。會根據(jù)不同的節(jié)點來各自解析。

@NonNullprivate NavDestination inflate(@NonNull Resources res, @NonNull XmlResourceParser parser, @NonNull AttributeSet attrs, int graphResId) throws XmlPullParserException, IOException {

Navigator navigator = mNavigatorProvider.getNavigator(parser.getName()); final NavDestination dest = navigator.createDestination();

dest.onInflate(mContext, attrs);

。。.。

final String name = parser.getName(); if (TAG_ARGUMENT.equals(name)) { // argument 節(jié)點 inflateArgumentForDestination(res, dest, attrs, graphResId); } else if (TAG_DEEP_LINK.equals(name)) { // deeplink 節(jié)點 inflateDeepLink(res, dest, attrs); } else if (TAG_ACTION.equals(name)) { // action 節(jié)點 inflateAction(res, dest, attrs, parser, graphResId); } else if (TAG_INCLUDE.equals(name) && dest instanceof NavGraph) { // include 節(jié)點 final TypedArray a = res.obtainAttributes(attrs, R.styleable.NavInclude); final int id = a.getResourceId(R.styleable.NavInclude_graph, 0); ((NavGraph) dest).addDestination(inflate(id)); a.recycle(); } else if (dest instanceof NavGraph) { // NavGraph 節(jié)點 ((NavGraph) dest).addDestination(inflate(res, parser, attrs, graphResId)); } }

return dest;}

通過獲取 NavInflater 來對其進行解析。解析后返回 NavGraph ,NavGraph是繼承自 NavDestination的。里面主要是保存了所有解析出來的節(jié)點信息。

最后簡單的總結下就是通過 NavHostFragment 獲取到NavContorl并存儲了相關的Navigator信息。通過各自的navigate方法進行頁面的跳轉。通過setGraph來解析配置的頁面節(jié)點信息,并封裝為NavGraph對象。里面通過SparseArray來存儲 Destination 信息。

自定義Navigator上文中我們說了需要自定義自己的 Navigator 用于承載 Fragment 。主要的實現(xiàn)思路就是繼承現(xiàn)有的 FragmentNavigator 并復寫其 navigate 方法,將其中的 replace 方法 替換為 show 和 hide 方法 來完成 Fragment 的切換。

那么我們自定義的 Navigator 如何才能讓系統(tǒng)識別呢?這也簡單,只要給我們的 類加上注解 @Navigator.Name(value) 那么他就是一個 Navigator 了。最后通過上文中分析的思路 在將其加入到NavigatorProvider 中 即可。

具體的自定義Navigator 已經(jīng)在項目 Android Jetpack架構開發(fā)組件化應用實戰(zhàn)(https://github.com/winlee28/Jetpack-WanAndroid) 中了,類名:FixFragmentNavigator。大家可以自行去看下。這里就將核心的代碼貼出來看下:

@Navigator.Name(“fixFragment”) //新的 Navigator 名稱class FixFragmentNavigator(context: Context, manager: FragmentManager, containerId: Int) : FragmentNavigator(context, manager, containerId) {

override fun navigate( destination: Destination, args: Bundle?, navOptions: NavOptions?, navigatorExtras: Navigator.Extras? ): NavDestination? {

。。.。

//ft.replace(mContainerId, frag)

/** * 1、先查詢當前顯示的fragment 不為空則將其hide * 2、根據(jù)tag查詢當前添加的fragment是否不為null,不為null則將其直接show * 3、為null則通過instantiateFragment方法創(chuàng)建fragment實例 * 4、將創(chuàng)建的實例添加在事務中 */ val fragment = mManager.primaryNavigationFragment //當前顯示的fragment if (fragment != null) { ft.hide(fragment) }

var frag: Fragment? val tag = destination.id.toString() frag = mManager.findFragmentByTag(tag) if (frag != null) { ft.show(frag) } else { frag = instantiateFragment(mContext, mManager, className, args) frag.arguments = args ft.add(mContainerId, frag, tag) }

。。.。 }}

自定義完成好,還需要將 mobile_navigation 的節(jié)點中遠 fragment 替換為 fixFragment 節(jié)點。并刪除布局文件中NavHostFragment 節(jié)點的

app:navGraph=“@navigation/mobile_navigation”

信息,因為我們需要手動將 FixFragmentNavigator 和 NavControl 進行關聯(lián)。

//添加自定義的FixFragmentNavigatornavController = Navigation.findNavController(this, R.id.nav_host_fragment)val fragment = supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as NavHostFragmentval fragmentNavigator = FixFragmentNavigator(this, supportFragmentManager, fragment??!.id)navController.navigatorProvider.addNavigator(fragmentNavigator)

navController.setGraph(R.navigation.mobile_navigation)

這樣就完成了自定義 Navigator 實現(xiàn)切換 Tab 的時候 Fragment 生命周期不會重新執(zhí)行了。

具體代碼邏輯詳見:Android Jetpack架構開發(fā)組件化應用實戰(zhàn)(https://github.com/winlee28/Jetpack-WanAndroid)

編輯:jq

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權轉載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學習之用,如有內(nèi)容侵權或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • Android
    +關注

    關注

    12

    文章

    3980

    瀏覽量

    132348
  • XML
    XML
    +關注

    關注

    0

    文章

    188

    瀏覽量

    34194
  • 源碼
    +關注

    關注

    8

    文章

    678

    瀏覽量

    30849

原文標題:Navigation源碼解析及自定義FragmentNavigator詳解

文章出處:【微信號:AndroidPush,微信公眾號:Android編程精選】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

    評論

    相關推薦
    熱點推薦

    mqtt dns解析失敗是為什么?

    解析域名的ip地址就能正常連上,而直接解析域名就不行,為什么呢
    發(fā)表于 09-16 06:38

    智能小車設計源碼和圖紙資料

    智能小車設計源碼和圖紙
    發(fā)表于 08-25 15:38 ?0次下載

    全新導航庫Jetpack Navigation 3發(fā)布

    在應用中的不同屏幕之間導航理應簡單明了。然而,構建穩(wěn)健、可擴展且賞心悅目的導航體驗卻并非易事。多年來,Jetpack Navigation 庫一直是開發(fā)者的重要工具,但隨著 Android 界面格局的演變,尤其是 Jetpack Compose 的興起,我們意識到是時候探索一種全新的解決方案了。
    的頭像 發(fā)表于 08-06 13:56 ?701次閱讀

    從“抓瞎”到“精準到0.01m”:我們是怎么調(diào)教機器人不亂動的?

    2025ICRASim2Rea獲獎隊伍給我們帶來MuJoCo+ROS2閉環(huán)控制與精準視覺抓取全流程解析項目主要包括Communication、Envs、Navigation
    的頭像 發(fā)表于 07-01 20:30 ?3203次閱讀
    從“抓瞎”到“精準到0.01m”:我們是怎么調(diào)教機器人不亂動的?

    鴻蒙5開發(fā)寶藏案例分享---PC開發(fā)案例解析

    鴻蒙PC/2in1開發(fā)寶藏指南:官方案例實戰(zhàn)解析 大家好呀! 最近在折騰鴻蒙的PC/2in1應用開發(fā),才發(fā)現(xiàn)官方文檔里藏了一堆超實用的案例!這些案例就像“隱藏關卡”,能幫你少踩80%的坑。今天我就把
    發(fā)表于 06-12 16:07

    鴻蒙5開發(fā)寶藏案例分享---一多分欄開發(fā)實踐

    ):清爽單欄 ? 折疊屏(md):優(yōu)雅雙欄 ? 平板(lg):專業(yè)三欄 ? 核心裝備庫 Navigation組件 - 路由容器三合一 // 自適應切換單雙欄的魔法 Navigation
    發(fā)表于 06-03 12:03

    harmony OS NEXT-Navagation基本用法

    # Navagation基本用法 > Navigation組件是路由導航的根視圖容器,一般作為Page頁面的根容器使用,其內(nèi)部默認包含了標題欄,內(nèi)容欄和公工具欄,其中內(nèi)容區(qū)默認首頁顯示導航內(nèi)容
    的頭像 發(fā)表于 04-27 17:39 ?556次閱讀

    STC單片機聲卡PCB和源碼資料

    STC單片機聲卡PCB和源碼資料
    發(fā)表于 04-03 11:14 ?0次下載

    CAN報文流程解析

    CAN報文流程解析,直流充電樁上的CAN通訊解析過程
    發(fā)表于 03-24 14:03 ?1次下載

    「極速探索HarmonyOS NEXT 」閱讀體驗】+Navigation

    Navigation 組件是頁面架構設計的基石,也是項目模塊化設計的重要組成部分,它主要包含導航(NavBar)和子頁(NavDestination)。導航頁包含內(nèi)容區(qū)、標題欄、菜單欄和工具欄,而子
    發(fā)表于 03-10 10:19

    SSM框架的源碼解析與理解

    的核心是控制反轉(IoC)和面向切面編程(AOP)。 源碼解析: Spring的源碼主要分為以下幾個部分: Bean容器: 負責實例化、配置和組裝對象。核心接口是 B
    的頭像 發(fā)表于 12-17 09:20 ?1257次閱讀

    源碼開放 智能監(jiān)測電源管理教程寶典!

    源碼開放,今天我們學習的是電源管理系統(tǒng)的核心功能模塊,手把手教你如何通過不同的技術手段實現(xiàn)有效的電源管理。
    的頭像 發(fā)表于 12-11 09:26 ?858次閱讀
    <b class='flag-5'>源碼</b>開放  智能監(jiān)測電源管理教程寶典!

    基于無操作系統(tǒng)的STM32單片機開發(fā)附源碼

    現(xiàn)在非常多的的MCU性能都還不錯,同時用戶也會去擴展一些外部RAM,這樣如果高效便捷的管理這些內(nèi)存是一個重要話題。 今天給大家分享一份源碼:基于無操作系統(tǒng)的STM32單片機開發(fā),功能強大,可申請
    的頭像 發(fā)表于 11-15 11:24 ?1694次閱讀

    索尼_imx678_19DV500驅(qū)動源碼

    hi3519dv500_IMX678驅(qū)動源碼
    發(fā)表于 11-01 10:36 ?6次下載

    ZCAN PRO解析的DBC Singal 起始位與XNET解析的起始位不同;解析的信號不符合大端邏輯

    上圖中的DBC文件使用記事本打開,Data_Field信號,起始位為23,長度為48,大端方式存儲;(按照這個方式存儲,明顯已經(jīng)溢出) 上圖為該信號在ZCANPRO軟件中打開,解析的起始位為23
    發(fā)表于 10-18 13:53