Navigation Architecture Component 學(xué)習(xí)筆記

Navigation Architecture Component 的一些概念

導(dǎo)航原則

任何應(yīng)用內(nèi)導(dǎo)航的目標(biāo)應(yīng)該是為用戶提供一致且可預(yù)測的體驗(yàn),為了實(shí)現(xiàn)這一目標(biāo),導(dǎo)航架構(gòu)組件可幫助您構(gòu)建符合以下幾個導(dǎo)航原則的應(yīng)用程序停巷。

  • 堆棧用于表示應(yīng)用程序的“導(dǎo)航狀態(tài)”
  • 前進(jìn)(Up)按鈕永遠(yuǎn)不會退出您的應(yīng)用
  • 前進(jìn)(Up)和后退(Back)在您的應(yīng)用程序任務(wù)中是等效的
    • 如果一直后退不能退出你的應(yīng)用胖眷,那就跟前進(jìn)沒什么兩樣了厌杜。
  • 深度鏈接到目標(biāo)或?qū)Ш降酵荒繕?biāo)應(yīng)產(chǎn)生相同的堆棧
    • 應(yīng)該是跟Activity任務(wù)棧管理一致的意思吧

目標(biāo) destination

一個destination是你在你的App上能導(dǎo)航到的任何地方奉呛,雖然destination通常是碎片(Fragment),但是Navigation Architecture Component也支持其它類型的destination:

  • Activity
  • 導(dǎo)航圖(navigation graph)或者次級導(dǎo)航圖(navigation subgraph)
  • 自定義的destination類型

操作 action

一個導(dǎo)航圖與目標(biāo)之間的聯(lián)系稱作操作,下圖就展示了一個應(yīng)用的導(dǎo)航圖夯尽,來自于一個包含了6個目標(biāo)瞧壮,目標(biāo)之間被5個action連接的應(yīng)用

一個導(dǎo)航圖

提示:如果要在Android Studio中使用導(dǎo)航架構(gòu)組件,則必須使用Android Studio 3.2 Canary 14或更高版本呐萌。不知道AS 3.2正式版好久出馁痴,應(yīng)該快了谊娇。

角色

NaviHostFragmnet

簡單例子

1. 實(shí)現(xiàn)類似首頁多Fragment的切換

效果

導(dǎo)航效果

這個業(yè)務(wù)很常見肺孤,一般用于應(yīng)用首頁,但如圖切換的四個Fragment并不是前進(jìn)與后退關(guān)系济欢,而是同級橫向切換關(guān)系赠堵。

以前的實(shí)現(xiàn)方案

我自己考慮的實(shí)現(xiàn)方案是優(yōu)先使用Android官方庫

  1. 使用FragmentTabHost

設(shè)置好Tab和對應(yīng)的Fragment,FragmentTabHost可以自動幫我們做tab和Fragment之間的綁定,切換Fragment的業(yè)務(wù)代碼也給我們封裝好了法褥。不過FragmentTabHost的切換方案是先add所有的fragment,再執(zhí)行dettach上一個fragment茫叭,attach要切換的fragment。所以每次切換到fragment半等,fragment的生命周期都會從onCreateView開始執(zhí)行揍愁,一直執(zhí)行到onResume,這一點(diǎn)也要考慮下杀饵。

  1. 使用BottomNavigationView + 自己寫的切換代碼

FragmentTabHost雖然幫我們實(shí)現(xiàn)了切換莽囤,但是切換Fragment的方式也是固定的,如果我想fragment之前已經(jīng)被add顯示過,之后再切換到它切距,不執(zhí)行它的onCreateView直接show行不行朽缎,當(dāng)然行,那就要自己的這份代碼了谜悟。

  1. 使用TabLayout + 自己寫的切換代碼

這個跟方案二差不多话肖,不過通常都搭配ViewPager使用

  1. 自定義Tab + 自己寫的切換代碼

這個較2,3方案就是導(dǎo)航的View也是自己定義葡幸,一般用于簡單的導(dǎo)航需求最筒。

試試BottomNavigationView+Navigation 新方案

我比較關(guān)注Navigation是怎樣實(shí)現(xiàn)Fragment切換的

1.創(chuàng)建NavHostFragment

NavHostFragment可以看作放置顯示Fragment的位置容器控件,本質(zhì)就是個Fragment。

跟Fragment的用法差不多训措,有兩種創(chuàng)建方式

  • 靜態(tài)方式,貼在xml布局文件上

比如我這里卢鹦,activity_main.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:orientation="vertical"
    android:layout_height="match_parent"
    tools:context=".MainActivity">
<fragment
    android:layout_width="match_parent"
    android:id="@+id/main_nav_host"
    android:name="androidx.navigation.fragment.NavHostFragment"
    app:navGraph="@navigation/nav_graph"
    app:defaultNavHost="true"
    android:layout_weight="1"
    android:layout_height="wrap_content"/>
<android.support.design.widget.BottomNavigationView
    android:layout_width="match_parent"
    android:id="@+id/main_bottom_nav"
    app:menu="@menu/main_bottom_nav"
    android:background="@drawable/main_nav_background"
    android:layout_height="60dp"/>
</LinearLayout>

Activity創(chuàng)建的時候會自動解析xml,把fragment添加進(jìn)Fragmentmanger,在Activity中悄泥,通過 (NavHostFragment) fragmentManager.findFragmentById(R.id.main_nav_host)就能獲取到你添加的NavHostFragment實(shí)例虏冻。

  • java代碼動態(tài)創(chuàng)建

官方例子:

NavHostFragment finalHost = NavHostFragment.create(R.navigation.example_graph);
getSupportFragmentManager().beginTransaction()
    .replace(R.id.nav_host, finalHost)
    .setPrimaryNavigationFragment(finalHost) // this is the equivalent to app:defaultNavHost="true"
    .commit();

NavHostFragment有create方法獲取一個新實(shí)例,然后添加到fragmentManager里弹囚,跟xml配置差不多厨相,還是需要一個容器,setPrimaryNavigationFragment(finalHost)是設(shè)置back鍵攔截

一些參數(shù)設(shè)置

BottomNavigationView的菜單參數(shù)鸥鹉,main_bottom_nav.xml:

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item
        android:id="@+id/oneFragment"
        android:icon="@drawable/ic_one"
        android:title="@string/title_one" />
    <item
        android:id="@+id/twoFragment"
        android:icon="@drawable/ic_two"
        android:title="@string/title_two" />
    <item
        android:id="@+id/threeFragment"
        android:icon="@drawable/ic_three"
        android:title="@string/title_three" />
    <item
        android:id="@+id/fourFragment"
        android:icon="@drawable/ic_four"
        android:title="@string/title_four" />
</menu>

四個Fragment

四個Fragment

代碼略

naviHostFragment的參數(shù)

NaviHostFragment的navGraph參數(shù)蛮穿,像菜單一樣也可用xml寫,這是很方便的毁渗,用xml就意味著AS有GUI界面能夠讓你拖拽點(diǎn)點(diǎn)點(diǎn)生成代碼践磅。
所以現(xiàn)在項(xiàng)目的res又有了新類型的資源文件:navigation

如果需要AS支持navigation資源文件編輯,還要再Settings里面開啟Enable Navigation Editor

開啟Enable Navigation Editor

比如我現(xiàn)在四個碎片的例子灸异,nav_graph.xml

<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    app:startDestination="@id/oneFragment">
    <fragment
        android:name="me.newtrekwang.navigationdemo.nav1.OneFragment"
        android:id="@+id/oneFragment"
        android:label="one_fragment"
        tools:layout="@layout/one_fragment"
        />
    <fragment
        android:name="me.newtrekwang.navigationdemo.nav2.TwoFragment"
        android:id="@+id/twoFragment"
        android:label="two_fragment"
        tools:layout="@layout/two_fragment"
        />
    <fragment
        android:id="@+id/threeFragment"
        android:name="me.newtrekwang.navigationdemo.nav3.ThreeFragment"
        android:label="three_fragment"
        tools:layout="@layout/three_fragment" />
    <fragment
        android:id="@+id/fourFragment"
        android:name="me.newtrekwang.navigationdemo.nav4.FourFragment"
        android:label="four_fragment"
        tools:layout="@layout/four_fragment" />
</navigation>

我把navigation里包含的每個標(biāo)簽看作是目標(biāo)府适,所以目標(biāo)就必須有自己的id等屬性,比如fragment肺樟,id為目標(biāo)id,name為目標(biāo)完成類名檐春,label是標(biāo)簽,layout方便AS解析預(yù)覽么伯。

nav_graph預(yù)覽

nav_graph預(yù)覽

可以看到預(yù)覽里疟暖,總動解析出host為MainActivity那個navHostFragment,以及四個我新定義的Fragment,oneFragment標(biāo)記為start,表示為起始顯示的Fragment.

因?yàn)楝F(xiàn)在是四個碎片之間橫向切換,所以他們之間沒有Action

BottomNavigationView與NavController綁定

回到MainActivity

public class MainActivity extends AppCompatActivity {
    
    private BottomNavigationView bottomNavigationView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        bottomNavigationView = findViewById(R.id.main_bottom_nav);
        BottomNavigationViewHelper.disableShiftMode(bottomNavigationView);

        NavHostFragment navHostFragment = (NavHostFragment)getSupportFragmentManager().findFragmentById(R.id.main_nav_host);
        NavController navController = navHostFragment.getNavController();
        NavigationUI.setupWithNavController(bottomNavigationView,navController);
    }
    @Override
    public boolean onSupportNavigateUp() {
        return Navigation.findNavController(this,R.id.main_nav_host).navigateUp();
    }
}

Navigation Architecture Component 的設(shè)計(jì)是導(dǎo)航都通過NaviController負(fù)責(zé)導(dǎo)航田柔,NavController可以通過三種靜態(tài)方法獲得

  • NavHostFragment.findNavController(Fragment)
  • Navigation.findNavController(Activity, @IdRes int viewId)
  • Navigation.findNavController(View)

NavHostFragment.findNavController(fragment)就是不斷遍歷fragment的getParentFragment()俐巴,直到找到一個NavHostFragment實(shí)例,然后返回它的navController.我們這里MainActivty很顯然可以直接獲取到navHostFragment硬爆,然后調(diào)用getNavController即刻欣舵。

Navigation.findNavController(Activity, @IdRes int viewId),Navigation.findNavController(View)其實(shí)是一個方法摆屯,最終會遍歷view的 view.getParent()邻遏,直到找到tag為NavController的View,然后返回controller虐骑。

所以獲取NavController的來源一種是NavHostFragment准验,另一種是tag為NaviController的View。

最后NavigationUI.setupWithNavController(bottomNavigationView,navController)廷没,NavigationUI把bottomNavigationView和navController綁定在一起糊饱,這樣一個碎片切換的業(yè)務(wù)幾行代碼就搞定了,大家可以實(shí)踐下颠黎,貌似比之前的方案少了很多代碼量另锋。

NavigationUI 怎么替我們綁定bottomNavigationView和navController的滞项?

NavigationUI替我們實(shí)現(xiàn)的切換是啥樣的?Fragment切換時的生命周期如何夭坪?令我有點(diǎn)小失望的是文判,每次切換到新Fragment都會new 一次Fragment,然后執(zhí)行它的生命周期方法室梅,是的戏仓,就是重新new 一次,再replace,你可以再Fragment里加幾個log驗(yàn)證一下亡鼠。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末赏殃,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子间涵,更是在濱河造成了極大的恐慌仁热,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,198評論 6 514
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件勾哩,死亡現(xiàn)場離奇詭異抗蠢,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)钳幅,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,334評論 3 398
  • 文/潘曉璐 我一進(jìn)店門物蝙,熙熙樓的掌柜王于貴愁眉苦臉地迎上來炎滞,“玉大人敢艰,你說我怎么就攤上這事〔崛” “怎么了钠导?”我有些...
    開封第一講書人閱讀 167,643評論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長森瘪。 經(jīng)常有香客問我牡属,道長,這世上最難降的妖魔是什么扼睬? 我笑而不...
    開封第一講書人閱讀 59,495評論 1 296
  • 正文 為了忘掉前任逮栅,我火速辦了婚禮,結(jié)果婚禮上窗宇,老公的妹妹穿的比我還像新娘措伐。我一直安慰自己,他們只是感情好军俊,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,502評論 6 397
  • 文/花漫 我一把揭開白布侥加。 她就那樣靜靜地躺著,像睡著了一般粪躬。 火紅的嫁衣襯著肌膚如雪担败。 梳的紋絲不亂的頭發(fā)上昔穴,一...
    開封第一講書人閱讀 52,156評論 1 308
  • 那天,我揣著相機(jī)與錄音提前,去河邊找鬼吗货。 笑死,一個胖子當(dāng)著我的面吹牛狈网,可吹牛的內(nèi)容都是我干的卿操。 我是一名探鬼主播,決...
    沈念sama閱讀 40,743評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼孙援,長吁一口氣:“原來是場噩夢啊……” “哼害淤!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起拓售,我...
    開封第一講書人閱讀 39,659評論 0 276
  • 序言:老撾萬榮一對情侶失蹤窥摄,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后础淤,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體崭放,經(jīng)...
    沈念sama閱讀 46,200評論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,282評論 3 340
  • 正文 我和宋清朗相戀三年鸽凶,在試婚紗的時候發(fā)現(xiàn)自己被綠了币砂。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,424評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡玻侥,死狀恐怖决摧,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情凑兰,我是刑警寧澤掌桩,帶...
    沈念sama閱讀 36,107評論 5 349
  • 正文 年R本政府宣布,位于F島的核電站姑食,受9級特大地震影響波岛,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜音半,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,789評論 3 333
  • 文/蒙蒙 一则拷、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧曹鸠,春花似錦煌茬、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,264評論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至叛薯,卻和暖如春浑吟,著一層夾襖步出監(jiān)牢的瞬間笙纤,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,390評論 1 271
  • 我被黑心中介騙來泰國打工组力, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留省容,地道東北人。 一個月前我還...
    沈念sama閱讀 48,798評論 3 376
  • 正文 我出身青樓燎字,卻偏偏與公主長得像腥椒,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子候衍,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,435評論 2 359

推薦閱讀更多精彩內(nèi)容