Android Jetpack從入門到精通(深度好文,值得收藏)

Android木子李老師發表於2020-10-17

前言

即學即用Android Jetpack系列Blog的目的是通過學習Android Jetpack完成一個簡單的Demo,本文是即學即用Android Jetpack系列Blog的第一篇。

記得去年第一次參加谷歌開發者大會的時候,就被Navigation的圖形導航介面給迷住了,一句臥槽就代表了小王的全部心情~,我們可以看一下來自網路的一張圖片:

Android Jetpack從入門到精通(深度好文,值得收藏)

 

所以,Android Jetpack學習之旅就開始了。

Android Jetpack從入門到精通(深度好文,值得收藏)

 

本人打算每週學習一個元件(上圖的左上區域),最後將所學的元件組成一個簡單的Demo。同時,剛剛過去的2019年穀歌開發者大會宣佈親兒子Kotlin成為開發Android的首選語言,所以本文的Demo也將都會採用Kotlin編寫。

本章結束後登入部分完成效果:

Android Jetpack從入門到精通(深度好文,值得收藏)

 

語言:KotlinDemo地址:https://github.com/mCyp/Hoo

目錄

一、簡介

1. 定義

Navigation是什麼呢?谷歌的介紹視訊上說:

Navigation是一個可簡化Android導航的庫和外掛

更確切的來說,Navigation是用來管理Fragment的切換,並且可以通過視覺化的方式,看見App的互動流程。這完美的契合了Jake Wharton大神單Activity的建議。

2. 優點

  • 處理Fragment的切換(上文已說過)
  • 預設情況下正確處理Fragment的前進和後退
  • 為過渡和動畫提供標準化的資源
  • 實現和處理深層連線
  • 可以繫結Toolbar、BottomNavigationView和ActionBar等
  • SafeArgs(Gradle外掛) 資料傳遞時提供型別安全性
  • ViewModel支援

3. 準備

如果想要進行下面的學習,你需要 3.2 或者更高的Android studio。

4. 學習方式

最好的學習方式仍然是通過官方文件,下面是官方的學習地址:谷歌官方教程:Navigation Codelab谷歌官方文件:Navigation官方Demo:Demo地址

二、實戰

在實戰之前,我們先來了解一下Navigation中最關鍵的三要素,他們是:

名詞解釋Navigation Graph(New XML resource)如我們的第一張圖所示,這是一個新的資原始檔,使用者在視覺化介面可以看出他能夠到達的Destination(使用者能夠到達的螢幕介面),以及流程關係。NavHostFragment(Layout XML view)當前Fragment的容器NavController(Kotlin/Java object)導航的控制者

可能我這麼解釋還是有點抽象,做一個不是那麼恰當的比喻,我們可以將Navigation Graph看作一個地圖,NavHostFragment看作一個車,以及把NavController看作車中的方向盤,Navigation Graph中可以看出各個地點(Destination)和通往各個地點的路徑,NavHostFragment可以到達地圖中的各個目的地,但是決定到什麼目的地還是方向盤NavController,雖然它取決於開車人(使用者)。

第一步 新增依賴

模組層的build.gradle檔案需要新增:

ext.navigationVersion = "2.0.0"
dependencies {
    //... 
    implementation "androidx.navigation:navigation-fragment-ktx:$rootProject.navigationVersion"
    implementation "androidx.navigation:navigation-ui-ktx:$rootProject.navigationVersion"
}

如果你要使用SafeArgs外掛,還要在專案目錄下的build.gradle檔案新增:

buildscript {
    ext.navigationVersion = "2.0.0"
    dependencies {
        classpath "androidx.navigation:navigation-safe-args-gradle-plugin:$navigationVersion"
    }
}

以及模組下面的build.gradle檔案新增:

apply plugin: 'kotlin-android-extensions'
apply plugin: 'androidx.navigation.safeargs'

第二步 建立navigation導航

  1. 建立基礎目錄:資原始檔res目錄下建立navigation目錄 -> 右擊navigation目錄New一個Navigation resource file
  2. 建立一個Destination,如果說navigation是我們的導航工具,Destination是我們的目的地,在此之前,我已經寫好了一個WelcomeFragment、LoginFragment和RegisterFragment,新增Destination的操作完成後如下所示:

除了視覺化介面之外,我們仍然有必要看一下里面的內容組成,login_navigation.xml:

<navigation
    ...
    android:id="@+id/login_navigation"
    app:startDestination="@id/welcome">

    <fragment
        android:id="@+id/login"
        android:name="com.joe.jetpackdemo.ui.fragment.login.LoginFragment"
        android:label="LoginFragment"
        tools:layout="@layout/fragment_login"
        />

    <fragment
        android:id="@+id/welcome"
        android:name="com.joe.jetpackdemo.ui.fragment.login.WelcomeFragment"
        android:label="LoginFragment"
        tools:layout="@layout/fragment_welcome">
        <action
            .../>
        <action
            .../>
    </fragment>

    <fragment
        android:id="@+id/register"
        android:name="com.joe.jetpackdemo.ui.fragment.login.RegisterFragment"
        android:label="LoginFragment"
        tools:layout="@layout/fragment_register"
        >

        <argument
            .../>
    </fragment>
</navigation>

我在這裡省略了一些不必要的程式碼。讓我們看一下navigation標籤的屬性:

屬性解釋app:startDestination預設的起始位置

第三步 建立NavHostFragment

我們建立一個新的LoginActivity,在activity_login.xml檔案中:

<androidx.constraintlayout.widget.ConstraintLayout
    ...>

    <fragment
        android:id="@+id/my_nav_host_fragment"
        android:name="androidx.navigation.fragment.NavHostFragment"
        app:navGraph="@navigation/login_navigation"
        app:defaultNavHost="true"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

</androidx.constraintlayout.widget.ConstraintLayout>

有幾個屬性需要解釋一下:

屬性解釋android:name值必須是androidx.navigation.fragment.NavHostFragment,宣告這是一個NavHostFragmentapp:navGraph存放的是第二步建好導航的資原始檔,也就是確定了Navigation Graphapp:defaultNavHost="true"與系統的返回按鈕相關聯

第四步 介面跳轉、引數傳遞和動畫

在WelcomeFragment中,點選登入和註冊按鈕可以分別跳轉到LoginFragment和RegisterFragment中。

Android Jetpack從入門到精通(深度好文,值得收藏)

 

image

這裡我使用了兩種方式實現:

方式一 利用ID導航

目標:WelcomeFragment攜帶key為name的資料跳轉到LoginFragment,LoginFragment接收後顯示。Have a account ? Login按鈕的點選事件如下:

btnLogin.setOnClickListener {
            // 設定動畫引數
            val navOption = navOptions {
                anim {
                    enter = R.anim.slide_in_right
                    exit = R.anim.slide_out_left
                    popEnter = R.anim.slide_in_left
                    popExit = R.anim.slide_out_right
                }
            }
            // 引數設定
            val bundle = Bundle()
            bundle.putString("name","TeaOf")
            findNavController().navigate(R.id.login, bundle,navOption)
}

後續LoginFragment的接收程式碼比較簡單,直接獲取Fragment中的Bundle即可,這裡不再出示程式碼。最後的效果:

Android Jetpack從入門到精通(深度好文,值得收藏)

 

方式二 利用Safe Args

目標:WelcomeFragment通過Safe Args將資料傳到RegisterFragment,RegisterFragment接收後顯示。再看一下已經展示過的login_navigation.xml:

<navigation
    ...>

    <fragment
        ...
        />

    <fragment
        android:id="@+id/welcome"
        >
        <action
            android:id="@+id/action_welcome_to_login"
            app:destination="@id/login"/>
        <action
            android:id="@+id/action_welcome_to_register"
            app:enterAnim="@anim/slide_in_right"
            app:exitAnim="@anim/slide_out_left"
            app:popEnterAnim="@anim/slide_in_left"
            app:popExitAnim="@anim/slide_out_right"
            app:destination="@id/register"/>
    </fragment>

    <fragment
        android:id="@+id/register"
        ...
        >

        <argument
            android:name="EMAIL"
            android:defaultValue="2005@qq.com"
            app:argType="string"/>
    </fragment>
</navigation>

細心的同學可能已經觀察到navigation目錄下的login_navigation.xml資原始檔中的action標籤和argument標籤,這裡需要解釋一下:action標籤

屬性作用app:destination跳轉完成到達的fragment的Idapp:popUpTo將fragment從棧中彈出,直到某個Id的fragment

argument標籤

屬性作用android:name標籤名字app:argType標籤的型別android:defaultValue預設值

點選Android studio中的Make Project按鈕,可以發現系統為我們生成了兩個類:

Android Jetpack從入門到精通(深度好文,值得收藏)

 

WelcomeFragment中的JOIN US按鈕點選事件:

btnRegister.setOnClickListener {
            val action = WelcomeFragmentDirections
                .actionWelcomeToRegister()
                .setEMAIL("TeaOf1995@Gamil.com")
            findNavController().navigate(action)
}

RegisterFragment中的接收:

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        // ...
        val safeArgs:RegisterFragmentArgs by navArgs()
        val email = safeArgs.email
        mEmailEt.setText(email)
}

以及效果:

Android Jetpack從入門到精通(深度好文,值得收藏)

 

需要提及的是,如果不用Safe Args,action可以由Navigation.createNavigateOnClickListener(R.id.next_action, null)方式生成,感興趣的同學可以自行編寫。

三、更多

Navigation可以繫結menus、drawers和bottom navigation,這裡我們以bottom navigation為例,我先在navigation目錄下新建立了main_navigation.xml,接著新建了MainActivity,下面則是activity_main.xml:

<LinearLayout
    ...>

    <fragment
        android:id="@+id/my_nav_host_fragment"
        android:name="androidx.navigation.fragment.NavHostFragment"
        android:layout_width="match_parent"
        app:navGraph="@navigation/main_navigation"
        app:defaultNavHost="true"
        android:layout_height="0dp"
        android:layout_weight="1"/>

    <com.google.android.material.bottomnavigation.BottomNavigationView
        android:id="@+id/navigation_view"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@android:color/white"
        app:itemIconTint="@color/colorAccent"
        app:itemTextColor="@color/colorPrimary"
        app:menu="@menu/menu_main"/>

</LinearLayout>

MainActivity中的處理也十分簡單:

class MainActivity : AppCompatActivity() {

    lateinit var bottomNavigationView: BottomNavigationView

    override fun onCreate(savedInstanceState: Bundle?) {
        //...
        val host: NavHostFragment = supportFragmentManager.findFragmentById(R.id.my_nav_host_fragment) as NavHostFragment
        val navController = host.navController
        initWidget()
        initBottomNavigationView(bottomNavigationView,navController)
    }

    private fun initBottomNavigationView(bottomNavigationView: BottomNavigationView, navController: NavController) {
        bottomNavigationView.setupWithNavController(navController)
    }

    private fun initWidget() {
        bottomNavigationView = findViewById(R.id.navigation_view)
    }
}

效果:

Android Jetpack從入門到精通(深度好文,值得收藏)

 

四、總結

Android Jetpack從入門到精通(深度好文,值得收藏)

 

現在都說網際網路寒冬,其實只要自身技術能力夠強,我們們就不怕!我這邊專門針對Android開發工程師整理了一套【Android進階學習視訊】、【全套Android面試祕籍】、【Android知識點PDF】。如有需要獲取資料文件的朋友,可以[點選我的GitHub]免費獲取

相關文章