Fragment 사용할 때 화면 전환을 사용하게 되는데 이 때 화면 전환 시 fragment의 재생성으로 인해 데이터가 사라지는 현상이 발생하게 되었습니다.
이를 방지하기 위해 상태 유지하기 위한 공부를 하게 되었습니다.
<LinearLayout
android:id="@+id/main_content"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:orientation="vertical"
/>
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="@+id/bottomNavigationView"
android:layout_width="match_parent"
android:layout_height="56dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:menu="@menu/bottom_menu"/>
저의 xml입니다. LinearLayout은 메인 컨텐츠 화면을 나타내는 곳입니다.
그리고 메인 액티비티 코드입니다.
class MainActivity : AppCompatActivity() {
private lateinit var mBinding : ActivityMainBinding
private lateinit var main_content : LinearLayout //xml의 content를 담는 layout
private lateinit var bottom_navigationview : BottomNavigationView
//Tag로 각 fragment를 구별합니다.
private val TAG_HOME = "home_fragment"
private val TAG_BLANK = "blank_fragment"
private val TAG_ACCOUNT = "account_fragment"
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
mBinding = ActivityMainBinding.inflate(layoutInflater)
val view = mBinding.root
setContentView(view)
//처음 시작 화면을 homeFragment로 설정(add로 생성 replace x)
setFragment(TAG_HOME, HomeFragment())
initBottomNavigationBar()
}
//bottomnavigation 초기화 세팅
private fun initBottomNavigationBar() {
main_content = findViewById(R.id.main_content)
bottom_navigationview = findViewById(R.id.bottomNavigationView)
//
mBinding.bottomNavigationView.setOnItemSelectedListener { item->
when(item.itemId){
R.id.home -> setFragment(TAG_HOME, HomeFragment())
R.id.contemplating -> setFragment(TAG_BLANK, BlankFragment())
R.id.account -> setFragment(TAG_ACCOUNT, AccountFragment())
}
true
}
}
//fragment 상태 유지를 위한 컨트롤 함수
fun setFragment(tag : String, fragment: Fragment) {
val manager : FragmentManager = supportFragmentManager
val bt = manager.beginTransaction()
//바텀 네비게이션의 tag(즉, 메뉴)가 선택 되었을 때 생성되있지 않을 경우
//바로 생성(add) 해줍니다.
if (manager.findFragmentByTag(tag) == null) {
bt.add(R.id.main_content, fragment, tag)
}
//코드 작성에 용이하게 따로 변수로 할당
val home = manager.findFragmentByTag(TAG_HOME)
val blank = manager.findFragmentByTag(TAG_BLANK)
val account = manager.findFragmentByTag(TAG_ACCOUNT)
//위에서 생성한 fragment들을
//우선 전부 hide 시킨 후
if (home != null) {
bt.hide(home)
}
if (blank != null) {
bt.hide(blank)
}
if (account != null) {
bt.hide(account)
}
//tag로 입력받은 fragment만 show를 통해 보여주도록 합니다.
if (tag == TAG_HOME) {
if (home != null) {
bt.show(home)
}
}
else if (tag == TAG_BLANK) {
if (blank != null) {
bt.show(blank)
}
}
else if (tag == TAG_ACCOUNT) {
if (account != null) {
bt.show(account)
}
}
bt.commitAllowingStateLoss()
}
}
commit은 activity가 state save 하기 전에 이루어져야 합니다. 그러나 state save 후에 commit이 호출된다면 예외 에러가 발생합니다. 만약 state save 와 관계없이 그리고 fragement 의 state 저장과 관련없게 작동하게 하려면 commit 대신 commitAllowingStateLoss() 를 호출해줘야 합니다.
출처:블로그
위 처럼 코드 작성 시 fragment의 상태(데이터, 위치 등)이 유지 되는 것을 확인할 수 있습니다.
참조 - [Android Kotlin] 안드로이드 코틀린 Fragment 상태 유지
fragment 상태 유지
먼저 숨겨버린 다음에, show하는 것 전부 좋은 방법이네요! 감사합니다 ^^