Fragment 란?
테블릿처럼 큰 화면에서 기존엔 Activity 두개를 띄우거나 했지만 서로 다른 생명주기를 가져서 관리가 힘들었다..!!
그래서, 동일한 액티비티 생명주기를 공유하지만 화면을 서로 다르게 사용하기 위해 Fragment 가 탄생했다.
Fragment 는 FragmentActivity 내의 어떤 동작 또는 사용자 인터페이스 일부를 나타낸다.
Activity 와 결합하여 창이 여러개인 UI 를 빌드할 수 있으며 하나의 Fragment 여러 Activity 에서 재사용할 수 있다.
자체적인 생명 주기를 가지며 자체 입력 이벤트를 수신하고 Activity 실행 중에 추가 및 삭제가 가능하다.
Fragment 는 항상 액티비티 내에서 호스팅되어야 하며 액티비티의 생명 주기에 직접적인 영향을 받는다!
- 액티비티 가 Paused -> 모든 프래그먼트도 Paused
- 액티비티가 Destoryed -> 모든 프래그먼트도 Destroyed
그러나! 액티비티가 실행 중인 동안 프래그먼트를 추가, 제거하는 등 개별적 조작이 가능하다.
이러한 조작을 프래그먼트 트랜잭션이라고 한다.
트랜잭션을 수행할 때 액티비티가 관리하는 백스택에도 추가할 수 있다.
백스택을 사용하면 사용자가 트랜잭션 을 거꾸로 돌리는 것도 가능하다.
Fragment 를 액티비티 레이아웃에 추가하면 해당 프래그먼트는 액티비티 View 계층 내에서 ViewGroup 에 들어가고 자체적인 뷰 레이아웃을 정의한다. ViewGroup 에 추가하거나 액티비티 레이아웃 파일에서 선언하면 액티비티 레이아웃에 삽입할 수 있다.
장점
- 액티비티에 종속적인 생명주기를 따르므로 부분 화면 관리에 용이함
- 시스템 개입이 없으므로 액티비티 사용시 보다 화면 전환의 부담이 적음
- 재활용 가능
Fragment Manager
프래그먼트를 추가, 삭제 또는 교체하고 백스택에 추가하는 등의 작업을 실행하는 클래스
* Jetpack Navigation 라이브러리를 사용하는 경우 FragmentManager 와 상호작용은 거의 필요하지 않음.
그러나 개발자가 알고 쓰는 것이 중요!
1. FragmentManager 에 엑세스
- Activity 에서 액세스
모든 FragmentActivity 및 그 서브클래스(ex: AppCompatActivity) 는 getSupportFragmentManager() 로 액세스 가능 - 프래그먼트는 하위 프래그먼트를 하나 이상 호스팅할 수 있다.
getChildFragmentManager() 를 통해 프래그먼트 하위 요소를 관리하는 FragmentManager 를 참조할 수 있다.
호스트 FragmentManager 에 액세스 하려면 getParentFragmentManager() 사용
FragmentManager 참조가 있으면 이를 사용하여 사용자에게 표시되는 프래그먼트를 조작할 수 있다.
2. FragmentManager 사용
FragmentManager 는 백 스택을 관리한다. 추가, 삭제 등의 작업은 FragmentTransaction 이라는 단일 단위로 함께 커밋된다. addToBackStack() 을 호출하여 트랜잭션을 프래그먼트 백 스택에 추가할 수 있다.
사용자가 뒤로가기 버튼을 누르면 FragmentManager.popBackStack() 을 호출하게 되고 최상위 프래그먼트가 트랜잭션이 스택에서 사라진다.
스택에 더 이상 FragmentTransaction 가 없고 개발자가 하위 프래그먼트를 사용하지 않는 경우 뒤로 이벤트가 액티비티까지 간다!
트랜잭션에 여러 개의 변경을 추가하고 (add() or remove()) addToBackStack() 을 호출하면 하나의 트랜잭션으로 백 스택에 추가되고 뒤로가기 누르면 한꺼번에 되돌려진다.
supportFragmentManager.commit {
replace<ExampleFragment>(R.id.fragment_container)
setReorderingAllowed(true)
addToBackStack("name") // name can be null
}
3. 기존 Fragment 찾기
findFragmentById() 또는 findFragmentByTag() 를 사용하여 레이아웃 컨테이너 내의 현재 프래그먼트 참조를 가져온다.
- findFragmentById() 로 찾기
supportFragmentManager.commit {
replace<ExampleFragment>(R.id.fragment_container)
setReorderingAllowed(true)
addToBackStack(null)
}
...
val fragment: ExampleFragment =
supportFragmentManager.findFragmentById(R.id.fragment_container) as ExampleFragment
- findFragmentByTag() 로 찾기
supportFragmentManager.commit {
replace<ExampleFragment>(R.id.fragment_container, "tag")
setReorderingAllowed(true)
addToBackStack(null)
}
...
val fragment: ExampleFragment =
supportFragmentManager.findFragmentByTag("tag") as ExampleFragment
4. Fragment Defendencies 제공
기본적으로 FragmentManager 는 프레임워크에서 제공하는 FragmentFactory 를 사용하여 프래그먼트의 새 인스턴스를 만든다. 이 기본 팩토리는 리플렉션을 사용하여 프래그먼트 인자가 없는 기본 생성자를 찾아 호출한다. 즉 기본 팩토리를 사용해서 프래그먼트에 Defendencies 를 제공할 수 없다.
종속 항목을 제공하거나 맞춤 생성자를 사용하려면 대신 맞춤FramentFactory 서브 클래스를 만들고FragmentFactory.instantiate 를 재정의 해야한다.
class MyFragmentFactory(val repository: DessertsRepository) : FragmentFactory() {
override fun instantiate(classLoader: ClassLoader, className: String): Fragment =
when (loadFragmentClass(classLoader, className)) {
DessertsFragment::class.java -> DessertsFragment(repository)
else -> super.instantiate(classLoader, className)
}
}
class MealActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
supportFragmentManager.fragmentFactory = MyFragmentFactory(DessertsRepository.getInstance())
super.onCreate(savedInstanceState)
}
}
위 방법 이외에도 동반 객체를 사용하여 프래그먼트 내에서 인자를 전달할 수 있다.
- 출처
https://developer.android.com/guide/fragments/fragmentmanager
'Android' 카테고리의 다른 글
[안드로이드] Flow 공식문서로 이해하기 - 1차 Flow 기초 (0) | 2023.08.25 |
---|---|
[안드로이드] ViewModel 테스트하기 : [우아한테크코스 5기 AN_베르] (0) | 2023.07.22 |
[안드로이드] Fragment Lifecycle (프래그먼트 생명 주기) (0) | 2023.05.30 |
[안드로이드] Room Local DB (0) | 2023.05.22 |
[안드로이드] Activity LifeCycle (0) | 2023.05.01 |