Android Jetpack之Navigation的使用

五月份的Google I/O大會(huì),Google推出了Android Jetpack架構(gòu)組件延欠,以幫助開(kāi)發(fā)者構(gòu)建更加優(yōu)質(zhì)的應(yīng)用隅津,Jetpack包含了以下組件

  • Navigation

用于管理APP頁(yè)面跳轉(zhuǎn)導(dǎo)航辩撑,切換fragment更加直觀,可視化界面展示fragment的切換流程圖

  • WorkManager

WorkManager API可以輕松指定可延遲的異步任務(wù)以及何時(shí)運(yùn)行它們方面。 這些API允許您創(chuàng)建任務(wù)并將其交給WorkManager立即運(yùn)行或在適當(dāng)?shù)臅r(shí)間運(yùn)行。 例如色徘,應(yīng)用可能需要不時(shí)從網(wǎng)絡(luò)下載新資源恭金。 使用這些類(lèi),您可以設(shè)置任務(wù)褂策,為其運(yùn)行選擇適當(dāng)?shù)沫h(huán)境(例如“僅在設(shè)備正在充電和在線”時(shí))横腿,并將其交給WorkManager以在滿(mǎn)足條件時(shí)運(yùn)行。 即使您的應(yīng)用程序強(qiáng)制退出或設(shè)備重新啟動(dòng)斤寂,該任務(wù)仍可保證運(yùn)行耿焊。

  • LifeCycle

每個(gè) Android 開(kāi)發(fā)者都應(yīng)該面對(duì)過(guò)生命周期問(wèn)題,即操作系統(tǒng)啟動(dòng)扬蕊、停止和銷(xiāo)毀 Activity搀别。這意味著開(kāi)發(fā)者需要根據(jù)生命周期的不同階段丹擎,有針對(duì)性地管理組件狀態(tài)尾抑,比如用于更新用戶(hù)界面的可觀察對(duì)象。生命周期管理(Lifecycles)幫助開(kāi)發(fā)者創(chuàng)建 “可感知生命周期的” 組件蒂培,讓其自己管理自己的生命周期再愈,從而減少內(nèi)存泄露和崩潰的可能性。生命周期庫(kù)是其他架構(gòu)組件(如 LiveData)的基礎(chǔ)护戳。

  • Paging

簡(jiǎn)單來(lái)說(shuō)翎冲,其實(shí)就是一個(gè)官方的分頁(yè)加載數(shù)據(jù)框架

  • Room

Room persistence庫(kù)為SQLite提供了一個(gè)抽象層,以便在利用SQLite的全部功能的同時(shí)實(shí)現(xiàn)更強(qiáng)大的數(shù)據(jù)庫(kù)訪問(wèn)媳荒。

navigation

本篇文章主要闡述Navigation如何管理TestNavigationActivity中的FragmentA抗悍、FragmentB、FragmentC三個(gè)fragment钳枕,以及fragment之間數(shù)據(jù)傳遞

注意:目前jetpack架構(gòu)組件需要運(yùn)行在Android Studio 3.2以上

navigation導(dǎo)航文件

在APP的res目錄下缴渊,創(chuàng)建一個(gè)navigation文件夾,在此文件夾下新增一個(gè)navigation
的xml文件鱼炒,此處新增一個(gè) test_navi.xml衔沼,內(nèi)容如下:


<?xml version="1.0" encoding="utf-8"?>
<navigation 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:id="@+id/test_navi"
    app:startDestination="@id/fragmentA">
    <fragment
        android:id="@+id/fragmentA"
        android:name="ywq.ares.jetpacklearning.ui.main.navigation.FragmentA"
        android:label="fragmentA"
        tools:layout="@layout/fragmentA">

        <action
            android:id="@+id/action_fragmentA_to_fragmentB"
            app:destination="@id/fragmentB"
            app:exitAnim="@android:anim/slide_out_right" />
    </fragment>
    <fragment
        android:id="@+id/fragmentB"

        android:name="ywq.ares.jetpacklearning.ui.main.navigation.FragmentB"
        android:label="fragmentB"
        tools:layout="@layout/fragmentB">
        <argument android:name="title" app:type="string" android:defaultValue="test"/>
        <argument android:name="num" app:type="integer" android:defaultValue="100"/>
        <action
            android:id="@+id/action_fragmentB_to_fragmentC"
            app:destination="@id/fragmentC"
            app:exitAnim="@android:anim/slide_out_right" />
    </fragment>
    <fragment
        android:id="@+id/fragmentC"

        android:name="ywq.ares.jetpacklearning.ui.main.navigation.FragmentC"
        android:label="fragmentC"
        tools:layout="@layout/fragmentC">
        <action
            android:id="@+id/action_fragmentC_to_fragmentA"
            app:destination="@id/fragmentA"
            app:exitAnim="@android:anim/slide_out_right" />
    </fragment>
</navigation>

很明顯,這是一個(gè)用于管理fragment跳轉(zhuǎn)意圖的文件

  • navigation根節(jié)點(diǎn) startDestination 表示第一個(gè)顯示的fragment
app:startDestination="@id/fragmentA"
  • fragment 節(jié)點(diǎn)
    • name屬性表示所屬的fragment類(lèi)
    • action 節(jié)點(diǎn) destination屬性用于指定下一個(gè)目標(biāo)fragment昔瞧、進(jìn)入退出動(dòng)畫(huà)等
    • argument 用于傳遞數(shù)據(jù)(下面會(huì)講)

在AS中指蚁,在navigation界面點(diǎn)擊Design標(biāo)簽,可以看到非常直觀的fragment切換流程

image.png

創(chuàng)建TestNavigationActivity

提示:必須繼承AppCompatActivity 或 FragmentActivity 否則會(huì)報(bào)以下異常

java.lang.RuntimeException: Unable to start activity ComponentInfo{ywq.ares.jetpacklearning/ywq.ares.jetpacklearning.ui.main.navigation.TestNavigationActivity}: android.view.InflateException: Binary XML file line #9: Binary XML file line #9: Error inflating class fragment
....
Caused by: android.app.Fragment$InstantiationException: Trying to instantiate a class androidx.navigation.fragment.NavHostFragment that is not a Fragment

activity布局文件

<?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"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent"> 
    <fragment
        android:id="@+id/fragment_first2"
        app:navGraph="@navigation/test_navi"
        android:name="androidx.navigation.fragment.NavHostFragment"
        app:defaultNavHost="true"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>
</LinearLayout>

其中fragment必須設(shè)置id,否則會(huì)報(bào)錯(cuò)

Caused by: java.lang.IllegalArgumentException: Binary XML file line #9: Must specify unique android:id, android:tag, or have a parent with an id for androidx.navigation.fragment.NavHostFragment

navGraph 用來(lái)指定上面的導(dǎo)航意圖文件 test_navi.xml

 app:navGraph="@navigation/test_navi"

name 必須指定為以下值自晰,表示這是一個(gè)可以切換fragment的控件

android:name="androidx.navigation.fragment.NavHostFragment"

假如你指定了其他fragment凝化,會(huì)報(bào)以下錯(cuò)誤

Caused by: java.lang.IllegalStateException: Fragment FirstFragment{b0bdbe5 #0 id=0x7f08004e} does not have a NavController set

defaultNavHost 表示是否攔截返回鍵,默認(rèn)為false, 假如頁(yè)面處于第二個(gè)fragment酬荞,這是按下返回鍵搓劫,會(huì)退出當(dāng)前activity而不是回到上一個(gè)fragment劣光。true則反之

app:defaultNavHost="true"

切換fragment

從FragmentA切換到FragmentB,以前的方式

getSupportFragmentManager().beginTransaction().show(fragmentB).hide(fragmentA).commit();

通過(guò)Navigation的方式

//在fragmentA中調(diào)用
NavHostFragment.findNavController(fragmentA).navigate(R.id.action_fragmentA_to_fragmentB)
//假如是通過(guò)點(diǎn)擊某個(gè)按鈕進(jìn)行切換的話(huà),也可以通過(guò)以下方式,id為目標(biāo)fragment的id
jumpBtn.setOnClickListener(Navigation.createNavigateOnClickListener(R.id.fragment_third));

數(shù)據(jù)傳遞

那么fragmentA如何傳遞數(shù)據(jù)到fragmentB呢糟把?

  1. 傳統(tǒng)方式

//fragmentA傳遞
var bundle = Bundle()
bundle.putString("title","xixi")
bundle.putInt("num",200)
NavHostFragment.findNavController(fragmentA).navigate(R.id.action_fragmentA_to_fragmentB,bundle)
//fragmentB接收 
val title = arguments?.getString("title")
val num = arguments?.getString("num")
 

以上方式存在一個(gè)弊端绢涡,就是接收方必須知道對(duì)應(yīng)的key才能正確接收對(duì)應(yīng)的值,這在團(tuán)隊(duì)協(xié)作上是極其不方便的遣疯。

  1. Navigation組件提供的方式雄可,安裝插件,編譯自動(dòng)生成參數(shù)對(duì)象

項(xiàng)目根目錄的builde.gradle文件

dependencies {
      ...
      classpath 'android.arch.navigation:navigation-safe-args-gradle-plugin:1.0.0-alpha02'
        ...
}

app目錄的build.gradle文件

apply plugin: 'androidx.navigation.safeargs'

在文章開(kāi)頭缠犀,navigation導(dǎo)航文件中可以設(shè)置fragment所接收的參數(shù)

<fragment
    android:id="@+id/fragmentB"

    android:name="ywq.ares.jetpacklearning.ui.main.navigation.FragmentB"
    android:label="fragmentB"
    tools:layout="@layout/fragmentB">

<argument android:name="title" app:type="string" android:defaultValue="test"/>
<argument android:name="num" app:type="integer" android:defaultValue="100"/>
</fragment>

rebuild項(xiàng)目数苫,會(huì)自動(dòng)生成對(duì)應(yīng)的參數(shù)類(lèi)(規(guī)則:fragment的類(lèi)名+Args),上面那個(gè)fragment生成的參數(shù)類(lèi)為FragmentBArgs

//fragmentA傳遞
val arg = FragmentBArgs.Builder()
arg.title = "haha"
arg.num = 100
NavHostFragment.findNavController(this).navigate(R.id.action_fragment1_to_fragment2,arg.build().toBundle())
//fragmentB接收
val args = SecondFragmentArgs.fromBundle(arguments)
val title = args.title
val num = args.num

相對(duì)于傳遞方式辨液,這種方式能夠非常清晰明了fragment所有需要接收的參數(shù)類(lèi)型乌妒,不用擔(dān)心字符串拼錯(cuò)而導(dǎo)致傳遞無(wú)法接收的問(wèn)題

遺留問(wèn)題

盡管通過(guò)Navigation方式管理Fragment的代碼簡(jiǎn)潔而且直觀,但是有一個(gè)非常致命的問(wèn)題研乒,就是同一個(gè)Fragment會(huì)被重復(fù)創(chuàng)建什乙,這樣會(huì)導(dǎo)致每次切換fragment的時(shí)候都會(huì)重新去請(qǐng)求數(shù)據(jù),非常浪費(fèi)系統(tǒng)資源燎悍,而且降低了APP的用戶(hù)體驗(yàn)敬惦,目前還找不到解決方案,大概以后官方會(huì)解決這個(gè)問(wèn)題吧~

下一篇谈山,我們來(lái)講一講Jetpack架構(gòu)組件中的WorkManager的用法

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末俄删,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子奏路,更是在濱河造成了極大的恐慌畴椰,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,968評(píng)論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件鸽粉,死亡現(xiàn)場(chǎng)離奇詭異斜脂,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)潜叛,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門(mén)秽褒,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人威兜,你說(shuō)我怎么就攤上這事销斟。” “怎么了椒舵?”我有些...
    開(kāi)封第一講書(shū)人閱讀 153,220評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵蚂踊,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我笔宿,道長(zhǎng)犁钟,這世上最難降的妖魔是什么棱诱? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,416評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮涝动,結(jié)果婚禮上迈勋,老公的妹妹穿的比我還像新娘。我一直安慰自己醋粟,他們只是感情好靡菇,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,425評(píng)論 5 374
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著米愿,像睡著了一般厦凤。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上育苟,一...
    開(kāi)封第一講書(shū)人閱讀 49,144評(píng)論 1 285
  • 那天较鼓,我揣著相機(jī)與錄音,去河邊找鬼违柏。 笑死博烂,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的勇垛。 我是一名探鬼主播脖母,決...
    沈念sama閱讀 38,432評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼士鸥,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼闲孤!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起烤礁,我...
    開(kāi)封第一講書(shū)人閱讀 37,088評(píng)論 0 261
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤讼积,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后脚仔,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體勤众,經(jīng)...
    沈念sama閱讀 43,586評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,028評(píng)論 2 325
  • 正文 我和宋清朗相戀三年鲤脏,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了们颜。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,137評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡猎醇,死狀恐怖窥突,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情硫嘶,我是刑警寧澤阻问,帶...
    沈念sama閱讀 33,783評(píng)論 4 324
  • 正文 年R本政府宣布,位于F島的核電站沦疾,受9級(jí)特大地震影響称近,放射性物質(zhì)發(fā)生泄漏第队。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,343評(píng)論 3 307
  • 文/蒙蒙 一刨秆、第九天 我趴在偏房一處隱蔽的房頂上張望凳谦。 院中可真熱鬧,春花似錦衡未、人聲如沸晾蜘。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,333評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)剔交。三九已至,卻和暖如春改衩,著一層夾襖步出監(jiān)牢的瞬間岖常,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,559評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工葫督, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留竭鞍,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,595評(píng)論 2 355
  • 正文 我出身青樓橄镜,卻偏偏與公主長(zhǎng)得像偎快,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子洽胶,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,901評(píng)論 2 345