본문 바로가기
Programando/Android

[Android/Kotlin] Fragment State 유지

🤦‍♀️ 문제 상황

BottomNavigationView에서 하단 메뉴를 선택할 때마다 supportFragmentManager.beginTransaction().replace()를 통해 Fragment를 교체하는데 이 방식으로 구현한 경우에는 하단 메뉴를 클릭할 때마다 Fragment가 OnCreate()되었습니다.

 

💊 해결 방법

  • 모든 Fragment 를 add 후에 show&hide 로 표시
    // 현재 표시되고 있는 Fragment
    private var visibleFragment: Fragment? = null

    private fun initFnb() {

        binding.fnb.run {
            setOnItemSelectedListener { item ->
                when(item.itemId) {
                    R.id.mHome -> {
                        changeFragemnt(homeFragment)
                        true
                    }
                    R.id.mCategory -> {
                        changeFragment(categoryFragment)
                        true
                    }
                    else ->
                        false
                }
            }

            selectedItemId = R.id.mHome
        }
    }

    private fun changeFragment(fr: Fragment) {
        visibleFragment = 
            // 보여줄 fragment 가 activity 에 add 되어 있지 않다면
            if(!fr.isAdded) {
                visibleFragment?.let { vf ->
                    // 현재 표시되는 fragment 를 hide 한 후에
                    // 보여줄 fragment 를 add
                    supportFragmentManager.beginTransaction().hide(af).add(R.id.feed, fr).addToBackStack(null).commit()
                } ?: run {
                    // 보여줄 fragment 를 add
                    supportFragmentManager.beginTransaction().add(R.id.feed, fr).commit()
                }

                // 현재 표시되는 fragment 를 변경
                fr
            } else {
                // add 되어있다면 현재 표시되는 fragment 를 hide 하고
                // 보여줄 fragment 는 show
                supportFragmentManager.beginTransaction().hide(activeFragment!!).show(fr).commit()

                // 현재 표시되는 fragment 를 변경
                fr
            }
    }

 

🤦‍♂️ 또 다른 문제

addToBackStack을 넣어 Back 버튼을 클릭하면 이전 Fragment로 이동하는 부분은 해결되었으나, 하단의 BottomNavigationView의 selectedItemId이 변하지 않는 문제가 발생했습니다.

 

🩹 해결 방법

    private val backButtonCallback = object: OnBackPressedCallback(true) {
        override fun handleOnBackPressed() {
            // backstack 에 있는 항목이 1 이상이면
            if(supportFragmentManager.backStackEntryCount > 0) {
                // 해당 stack 을 pop 하고
                supportFragmentManager.popBackStack()
                // 현재 fragment 의 id 와 같은 fragment 를 찾아
                // BottomNavigationView 의 selectedItemId 를 해당 fragment 로 변경
                when(supportFragmentManager.findFragmentById(R.id.feed)?.id) {
                    homeFragment.id -> {
                        binding.fnb.selectedItemId = R.id.mHome
                    }
                    categoryFragment.id -> {
                        binding.fnb.selectedItemId = R.id.mCategory
                    }
                }
            } else {
                finish()
            }
        }
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        ...

        this.onBackPressedDispatcher.addCallback(this, backButtonCallback)
    }
반응형