룬아님의 취중코딩

Android Navigation Component save state on Bottom Navigation 본문

개발/안드로이드 개발

Android Navigation Component save state on Bottom Navigation

룬아님 2019. 11. 26. 17:33

Bottom Navigation과 Navigation Component를 같이 사용했을 때 네비게이션 버튼을 누를 때마다 onCreate가 불린다.
이유는 Navigation Component에서 화면이 변경 될 때에 show, hide 로직이 아닌 replace를 사용하기 때문인데
지금은 override도 불가능하고 기본적으로 지원하지도 않기 때문에 추후 업데이트를 지켜봐야 한다.

하지만 구글에서 제공한 Android Architecture Components Advanced Navigation Sample에서 navigation graph를 분할하여 상태를 저장할 수 있도록 하는 예제를 공개하였다.

하지만 이 역시 네비게이션 버튼에 의한 프래그먼트 이동에 한에서만 상태를 저장하지 navigation component를 이용하여 이동하고 백스탭으로 돌아오는 것은 아직도 onCreate를 호출한다.

위의 예제를 사용하기 위해서는

 

1. build.gradle

    implementation 'androidx.navigation:navigation-fragment:2.0.0'
    implementation 'androidx.navigation:navigation-ui:2.0.0'
    implementation 'androidx.navigation:navigation-fragment-ktx:2.0.0'
    implementation 'androidx.navigation:navigation-ui-ktx:2.0.0'

    implementation 'androidx.core:core-ktx:1.1.0'
    implementation "androidx.fragment:fragment:1.2.0-rc02"

 

2. 메뉴에서 설정한 바텀 네비게이션 아이템의 id와 navigation의 id가 일치하여야 작동한다.

<!-- bottom_nav_menu.xml !-->

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">

    <item
        android:id="@+id/notices"
        android:icon="@drawable/ic_home_black_24dp"
        android:title="@string/title_notice" />

    <item
        android:id="@+id/setting"
        android:icon="@drawable/ic_dashboard_black_24dp"
        android:title="@string/title_setting" />

</menu>



<!-- notices.xml !-->

<?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/notices"
    app:startDestination="@+id/navigation_notice">
    <fragment
        android:id="@+id/navigation_notice"
        android:name="com.mashup.app.notices.NoticesFragment"
        android:label="@string/title_notice"
        tools:layout="@layout/notices_fragment" />
</navigation>

 

3. activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/container"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <com.google.android.material.bottomnavigation.BottomNavigationView
        android:id="@+id/nav_view"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginStart="0dp"
        android:layout_marginEnd="0dp"
        android:background="@color/colorWhite"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:menu="@menu/bottom_nav_menu" />

    <androidx.fragment.app.FragmentContainerView
        android:id="@+id/nav_host_container"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        app:layout_constraintBottom_toTopOf="@id/nav_view"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <View
        android:id="@+id/bottom_line"
        android:layout_width="match_parent"
        android:layout_height="4dp"
        app:layout_constraintBottom_toTopOf="@id/nav_view"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        android:background="@drawable/shadow_bottom_to_up" />

</androidx.constraintlayout.widget.ConstraintLayout>

 

4. MainActivity.kt

class MainActivity : AppCompatActivity() {

    private var currentNavController: LiveData<NavController>? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        if (savedInstanceState == null) {
            setupBottomNavigationBar()
        } // Else, need to wait for onRestoreInstanceState
    }

    override fun onRestoreInstanceState(savedInstanceState: Bundle?) {
        super.onRestoreInstanceState(savedInstanceState)
        // Now that BottomNavigationBar has restored its instance state
        // and its selectedItemId, we can proceed with setting up the
        // BottomNavigationBar with Navigation
        setupBottomNavigationBar()
    }

    /**
     * Called on first creation and when restoring state.
     */
    private fun setupBottomNavigationBar() {
        val bottomNavigationView = findViewById<BottomNavigationView>(R.id.nav_view) //BottomNavigationView의 id

        val navGraphIds = listOf(R.navigation.notices, R.navigation.setting)//graph들의 id

        // Setup the bottom navigation view with a list of navigation graphs
        val controller = bottomNavigationView.setupWithNavController(
            navGraphIds = navGraphIds,
            fragmentManager = supportFragmentManager,
            containerId = R.id.nav_host_container, //FragmentContainerView의 id
            intent = intent
        )

        // Whenever the selected controller changes, setup the action bar.
        /*controller.observe(this, Observer { navController ->
            setupActionBarWithNavController(navController)
        })*/
        //액션바 관련 코드 (액션바를 사용하지 않기 때문에 주석처리)
        currentNavController = controller
    }

    override fun onSupportNavigateUp(): Boolean {
        return currentNavController?.value?.navigateUp() ?: false
    }
}

 

5. NavigationExtensions

https://github.com/android/architecture-components-samples/blob/master/NavigationAdvancedSample/app/src/main/java/com/example/android/navigationadvancedsample/NavigationExtensions.kt

 

android/architecture-components-samples

Samples for Android Architecture Components. . Contribute to android/architecture-components-samples development by creating an account on GitHub.

github.com

 

반응형
Comments