버그 잡이

(ViewModel+LiveData)Bottom Navigation 수직/수평 전환시 fragment 초기화 문제 해결 #configuration change 본문

모던 안드로이드/Udacity Android with kotlin

(ViewModel+LiveData)Bottom Navigation 수직/수평 전환시 fragment 초기화 문제 해결 #configuration change

버그잡이 2020. 4. 16. 20:21

Bottom Navigation을 사용할때 수직/수평 화면 전환을 하면 activity가 소멸했다 다시 생성되기 때문에

 

내가 두번째 menu에 있더라도 onCreate에서 setting 한 첫번째 Fragment로 변경된다.

 

ViewModel+ LiveData 를 활용하여 이를 해결할 수 있다.

 

 

 

 

 

1. BottomNavigationViewModel

 

- fragment의 상태를 나타내는 LiveData 변수를 만들어준다.

 

- 초기화는 여기서 진행한다 -> ViewModel은 configuration change때 소멸되지 않기 때문에 상태를 유지할 수 있다.

 

- navigation menu 클릭시 updateFragmentStatus() 메서드로 상태만 최신화 해준다.

 

class BottomNavigationViewModel : ViewModel(){

    private var _fragmentStatus = MutableLiveData<Int>()
    val fragmentStatus : LiveData<Int>
        get() = _fragmentStatus

    init {
        _fragmentStatus.value = 1
    }

    fun updateFragmentStatus(num: Int){
        _fragmentStatus.value = num
    }

}

 

 

2. BottomNavigationActivity

 

- 클릭시 ViewModel의 LiveData(fragmentStatus)만 최신화 해주고 

- fragment 전환은 LiveData(fragmentStatus) 옵저버를 통해서 진행한다.

class BottomNavigationActivity : AppCompatActivity() {

    private val viewModel: BottomNavigationViewModel by lazy {
        ViewModelProviders.of(this).get(BottomNavigationViewModel::class.java)
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_bottom_navigation)

//fragmentStatus liveData를 관찰하고 변화시 fragment 변경
        viewModel.fragmentStatus.observe(this, Observer {
            when(it){
                1 -> {
                    val todoFragment = TodoFragment()
                    loadFragment(todoFragment)
                }
                2 -> {
                    val blogFragment = BlogFragment()
                    loadFragment(blogFragment)
                }
            }
        })

        //네비게이션 클릭 리스너(클릭시 해당 프래그먼트로 이동)
        setNavigationItemClickListener()

    }


    private fun setNavigationItemClickListener(){
        bottom_navigation.setOnNavigationItemSelectedListener {
            when (it.itemId) {
                R.id.navigation_todo -> {
                    viewModel.updateFragmentStatus(1)       //여기서는 fragment 상태만 업데이트 하고 최신화는 observer에서 하도록 한다.
                    return@setOnNavigationItemSelectedListener true
                }
                R.id.navigation_blog -> {
                    viewModel.updateFragmentStatus(2)
                    return@setOnNavigationItemSelectedListener true
                }
            }
            false
        }
    }


    private fun loadFragment(fragment: Fragment){
        val transaction = supportFragmentManager.beginTransaction()
        transaction.replace(R.id.container, fragment)
        transaction.addToBackStack(null)
        transaction.commit()
    }
    
}

 

반응형
Comments