FragmentManager
앱 프래그먼트에서 프래그먼트를 추가, 삭제 또는 교체하고 백 스텍에 추가하는 등의 작업을 실행하는 클래스
FragmentManager에 접근
FragmentManager는 액티비티당 FragmentManager 하나가 존재하기 때문에 이를 가져와서 사용하면 됨
액티비티에서 getSupportFragmentManager() 매서드 사용
프래그먼트에선 하위 프래그먼트가 존재할 시 getChildFragmentManager() 매서드 사용
상위 프래그먼트의 FragmentManager에 접근할려면 getParentFragmentManager() 메서드 사용
FragmentTransaction
FragmentManager를 통하여 프래그먼트를 추가, 삭제하기 위한 작업
beginTransaction 매서드를 사용하여 시작하기도 하지만 commit 을 사용하면 스코프 매서드로 바로 사용 가능하다.
val fragmentManager = supportFragmentManager
fragmentManager.commit {
add(R.id.hostFragment, HostFragment())
}
Commit에 관하여
1.프래그먼트 추가, 교체, 삭제 작업을 명시했으면 반드시 commit 해야 하는 이유
2. commit 를 해야지만 FragmentManager가 해당 FragmentTransaction을 수행함
3. 비동기로 처리되기 때문에 commit을 호출하자마자 Transaction이 즉시 수행되는 것이 아니라 메인 스레드에 예약됨
4. 메인 스레드가 예약된 Transaciton을 수행할 준비가 되면 비로소 그 때 Transaction이 수행되며 명시한 Fragment 작업들이 실행됨
5. Transaction이 비동기가 되야 한다면 커밋 즉시 수행하는 commitNow()를 호출하면 됨
=> 백스택을 추가하는데 문제가 발생할 수 있음
Add에 관하여
1. 프래그먼트를 추가하는 작업
2. add로 수행되는 프래그먼트 추가 작업은 호스트 Activity의 수명 주기에 프래그먼트 수명 주기를 추가하는 것임
3. 프래그먼트 onAttach() 때 Fragment가 자신의 호스트인 Activity에 붙게 되고 onCreateView에서 프래그먼트 View가 inflate가 되며 Fragment Container 위치에 보이게 됨
Replace
1. 프래그먼트를 교체하는 작업
2. 교체가 프래그먼트 하나랑 다른 하나를 교체하는 것이 아니라 프로퍼티로 받는 프래그먼트를 제외한 나머지 모든 프래그먼트를 remove를 하게 되는 작업
Show & Hide
1. 이미 프래그먼트 컨테이너에 추가 되어잇는 프래그먼트의 UI 를 감추거나 보이게 해주는 작업
2. 프래그먼트 수명에 영향을 주지 않고 오직 Visibility에만 영향
=> 프래그먼트가 생성되거나 삭제되는 것이 아니기 때문에 상태가 유지되어 있음
3. 계층 구조가 유지됨
Attach & Detach
1. Detach는 프래그먼트의 UI를 분리하여 파괴시키나 메모리에 유지됨 (remove는 메모리에서 삭제!)
2. Attach는 분리되어있던 프래그먼트의 UI를 다시 붙임
3. Attach하게 되면 프래그먼트 컨테이너의 가장 위에 쌓임
=> 수명 주기에 영향을 줌
백스택
안드로이드 플랫폼에서 백스택이라는 자료구조를 통해 액티비티의 히스토리를 저장함
만약, 메인 액티비티에서 Second액티비티로 Intent를 이용하여 넘어갔다면 맨 밑에 메인이 있고 그 위에 Second가 존재
이 때 뒤로가기를 누르면 Second액티비티는 Pop이 되어 사라지고 메인 액티비티가 나타남
즉, Stack의 Peek만 보여주는 구조라고 생각하면 됨
FragmentManager의 백스택
위 안드로이드 플랫폼이 관리하는 백스텍에 FragmentManager의 Transaction도 포함시킴
하는 이유는 사용자가 뒤로 가기 버튼을 눌렀을 때 이전 Fragment 또한 표시해주기 위함
액티비티는 자동으로 추가되지만 프래그먼트 트랜잭션은 아님
그걸 해주는 메서드가 addToBackStack()
뷰모델, 하단 네비게이션 뷰를 사용하여 프래그먼트 전환
PageType.kt
enum class PageType {
HOME,
TEST
}
ViewModel.kt
class ViewModel : androidx.lifecycle.ViewModel(){
private var _pageType = MutableLiveData<PageType>()
val pageType : LiveData<PageType> get() = _pageType
fun updageFragmentStatus(pageType: PageType){
_pageType.value = pageType
}
}
MainActivity.kt
package com.example.myandroidstudy.view.main
import android.os.Bundle
import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.Fragment
import androidx.fragment.app.commit
import androidx.lifecycle.Observer
import androidx.lifecycle.asLiveData
import com.example.myandroidstudy.R
import com.example.myandroidstudy.databinding.ActivityMainBinding
import com.example.myandroidstudy.model.PageType
import com.example.myandroidstudy.model.ViewModel
import com.example.myandroidstudy.model.preferences.CountManager
import com.example.myandroidstudy.model.preferences.dataStore
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers.IO
import kotlinx.coroutines.launch
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
private val viewModel : ViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
viewModel.updageFragmentStatus(PageType.HOME)
viewModel.pageType.observe(this, Observer {
when(it){
PageType.HOME ->{
loadFragment(HomeFragment())
}
PageType.TEST ->{
loadFragment(TestFragment())
}
}
})
setNavigationItemClickListener()
}
private fun setNavigationItemClickListener() {
binding.navigationView.setOnItemSelectedListener { item ->
when (item.itemId) {
R.id.navi_homeFragment -> {
viewModel.updageFragmentStatus(PageType.HOME)
return@setOnItemSelectedListener true
}
R.id.navi_testFragment -> {
viewModel.updageFragmentStatus(PageType.TEST)
return@setOnItemSelectedListener true
}
}
false
}
}
private fun loadFragment(fragment: Fragment) {
val transaction = supportFragmentManager.beginTransaction()
transaction.replace(R.id.mainFrameLayout, fragment)
transaction.addToBackStack(null)
transaction.commit()
}
private fun addFragment(fragment: Fragment){
val transaction = supportFragmentManager.beginTransaction()
transaction.add(R.id.mainFrameLayout, fragment)
transaction.addToBackStack(null)
transaction.commit()
}
}
'Android' 카테고리의 다른 글
[안드로이드] 서비스 (0) | 2023.07.22 |
---|---|
[안드로이드] 콘텐츠 제공자(ContentProvider) 와 콘텐츠 리졸버(ContentResolver) (0) | 2023.07.16 |
[안드로이드]DataStore에 대하여 (0) | 2023.07.02 |
[안드로이드]Intent에 관하여 (0) | 2023.06.01 |
[안드로이드]RecyclerView에 관하여 (0) | 2023.05.23 |