코틀린 fragment 화면 전환시 이전 화면 유지하기

2023. 12. 17. 18:46- 안드로이드/kotlin

fragment를 사용한 바텀 네비게이션에서 화면을 전환하고 다시 원래 화면으로 돌아오면 화면이 유지 되지 않고 초기화 되는 문제점이 발견되었습니다. 이번 포스팅에서 화면 전환을 해도 fragment가 유지 되도록 코드를 짜보겠습니다. 

 

먼저 fragment xml을 만들어 줍니다.

fragment_monitoring.xml

 

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".fragment.MonitoringFragment">

    <TextView
        android:id="@+id/textViewTest"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="모니터링"
        android:layout_centerInParent="true"/>

    <Button
        android:id="@+id/buttonTest"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="버튼"/>


</RelativeLayout>

 

 

MonitoringFragment.class

 

class MonitoringFragment : Fragment() {

    private var mBinding: FragmentMonitoringBinding? = null
    private val binding get() = mBinding!!

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        mBinding = FragmentMonitoringBinding.inflate(inflater, container, false)
        binding.buttonTest.setOnClickListener {
            binding.textViewTest.text = "클릭됨"
        }
        return binding.root
    }

    override fun onDestroyView() {
        mBinding = null
        super.onDestroyView()
    }
}

 

 

위와 같은 방식으로 필요한 페이지의 프래그 먼트를 만들어 줍니다.

 

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"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".ActivityMain">

    <FrameLayout android:layout_width="0dp"
        android:layout_height="0dp"
        android:id="@+id/fragmentHost"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintBottom_toTopOf="@+id/bottomNavi"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"/>

    <com.google.android.material.bottomnavigation.BottomNavigationView
        android:id="@+id/bottomNavi"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        style="@style/Widget.MaterialComponents.BottomNavigationView.PrimarySurface"
        app:menu="@menu/navi_menu"
        android:clickable="false"
        app:itemIconTint="@drawable/menu_click_color"
        app:itemTextColor="@drawable/menu_click_color"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"/>


</androidx.constraintlayout.widget.ConstraintLayout>

 

 

ActivityMain.class

 

class ActivityMain : AppCompatActivity() {

    private var mBinding: ActivityMainBinding? = null
    private val binding get() = mBinding!!
    private val fragmentManager = supportFragmentManager
    private var monitoringFragment: MonitoringFragment? = null
    private var analysisFragment: AnalysisFragment? = null
    private var premiumFragment: PremiumFragment? = null
    private var profileFragment: ProfileFragment? = null
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        mBinding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)

        binding.bottomNavi.labelVisibilityMode = LABEL_VISIBILITY_LABELED   // label 항상 보이기
        initBottomNavigation()
    }

    private fun initBottomNavigation(){
        // 최초로 보이는 프래그먼트
        monitoringFragment = MonitoringFragment()
        fragmentManager.beginTransaction().replace(R.id.fragmentHost,monitoringFragment!!).commit()

        binding.bottomNavi.setOnItemSelectedListener {

            when(it.itemId){
                R.id.monitoringFragment ->{
                    if(monitoringFragment == null){ // null일때만 한번 만들고 이후에는 생성된 객체를 사용하기 때문에 초기화 안됨
                        monitoringFragment = MonitoringFragment()
                        fragmentManager.beginTransaction().add(R.id.fragmentHost,monitoringFragment!!).commit()
                    }
                    if(monitoringFragment != null) fragmentManager.beginTransaction().show(monitoringFragment!!).commit()
                    if(analysisFragment != null) fragmentManager.beginTransaction().hide(analysisFragment!!).commit()
                    if(premiumFragment != null) fragmentManager.beginTransaction().hide(premiumFragment!!).commit()
                    if(profileFragment != null) fragmentManager.beginTransaction().hide(profileFragment!!).commit()

                    return@setOnItemSelectedListener true
                }
                R.id.analysisFragment ->{
                    if(analysisFragment == null){
                        analysisFragment = AnalysisFragment()
                        fragmentManager.beginTransaction().add(R.id.fragmentHost,analysisFragment!!).commit()
                    }
                    if(monitoringFragment != null) fragmentManager.beginTransaction().hide(monitoringFragment!!).commit()
                    if(analysisFragment != null) fragmentManager.beginTransaction().show(analysisFragment!!).commit()
                    if(premiumFragment != null) fragmentManager.beginTransaction().hide(premiumFragment!!).commit()
                    if(profileFragment != null) fragmentManager.beginTransaction().hide(profileFragment!!).commit()

                    return@setOnItemSelectedListener true
                }
                R.id.premiumFragment ->{
                    if(premiumFragment == null){
                        premiumFragment = PremiumFragment()
                        fragmentManager.beginTransaction().add(R.id.fragmentHost,premiumFragment!!).commit()
                    }
                    if(monitoringFragment != null) fragmentManager.beginTransaction().hide(monitoringFragment!!).commit()
                    if(analysisFragment != null) fragmentManager.beginTransaction().hide(analysisFragment!!).commit()
                    if(premiumFragment != null) fragmentManager.beginTransaction().show(premiumFragment!!).commit()
                    if(profileFragment != null) fragmentManager.beginTransaction().hide(profileFragment!!).commit()

                    return@setOnItemSelectedListener true
                }
                R.id.profileFragment ->{
                    if(profileFragment == null){
                        profileFragment = ProfileFragment()
                        fragmentManager.beginTransaction().add(R.id.fragmentHost,profileFragment!!).commit()
                    }
                    if(monitoringFragment != null) fragmentManager.beginTransaction().hide(monitoringFragment!!).commit()
                    if(analysisFragment != null) fragmentManager.beginTransaction().hide(analysisFragment!!).commit()
                    if(premiumFragment != null) fragmentManager.beginTransaction().hide(premiumFragment!!).commit()
                    if(profileFragment != null) fragmentManager.beginTransaction().show(profileFragment!!).commit()

                    return@setOnItemSelectedListener true
                }
                else ->{
                    return@setOnItemSelectedListener true
                }
            }
        }
    }
}

 

각 프래그먼트 monitoringFragment등을 지역변수가 아닌 멤버변수로 생성하여 데이터를 유지 하도록 합니다. 각 프래그먼트 객체 생성은 null일 경우에 한번만 생성 하고 null이 아니라면 기존에 생성 했던 프래그먼트를 재사용 하며 화면을 유지 할 수 있습니다.