FrameLayout에서 Fragment 올바르게 사용하기

DoDoBest

·

2024. 5. 2. 16:05

FrameLayout에서 Fragment를 사용하는 방법

안드로이드 공식 문서에서 Fragment를 위한 container로 FragmentContainerView 사용을 강력하게 권장합니다.

It is strongly recommended to always use a FragmentContainerView as the container for fragments, as FragmentContainerView includes fixes specific to fragments that other view groups such as FrameLayout do not provide.
https://developer.android.com/guide/fragments/create#add

 

그럼에도 FrameLayout에서 Fragment를 사용해봅시다. FrameLayout은 FragmentContainerView에서 제공하는 name attribute를 제공하지 않습니다. 그래서 코드에서 Fragment를 지정해줘야 합니다.

 

class MainActivity : AppCompatActivity() {
    private lateinit var binding: ActivityMainBinding

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)

        supportFragmentManager.beginTransaction()
            .add(R.id.frame_layout, SearchFragment())
            .commit()
    }
}

 

위 코드는 어떤 문제가 있을까요? Configuration Change가 발생할 때마다, 화면에 있는 SearchFragment가 다시 복원되고 새로운 SearchFragment가 FrameLayout에 추가되어, 여러 SearchFragment가 중첩되어 보이게 됩니다.

 

아래 GIF는 소프트웨어 키보드로 감자를 입력한 후, 블루투스 키보드를 연결하고 고구마를 입력한 결과입니다.

 

 

블루투스 키보드를 연결하면 Android Manifest에서 별도로 설정하지 않는한 Configuration Change가 발생합니다.

 

 

 

 

 

Layout Inspector로 확인해보면 FrameLayout에 SearchFragment가 Configuration Change 횟수만큼 추가로 생성된 것을 확인할 수 있습니다.

 

 

기존 Fragment는 어떻게 복원된 걸까요?

 

화면에 존재하는 Fragment가 복원되는 방법

Configuration change가 발생하면 Activity가 파괴되고 재생성됩니다. 파괴되는 시점에 화면에 존재하는 Fragment는 savedInstanceState에 저장됩니다. Activity가 다시 생성되면 전달된 savedInstanceState를 이용해 Fragment가 복원됩니다. 직접 복원하는 코드를 작성할 필요 없이 자동으로 복원됩니다.

 

그래서 Configuration Change가 발생하면 기존의 Fragment가 복원되고, Transaction add 함수를 통해 새로운 Fragment가 FrameLayout에 추가되었던 것입니다.

 

올바른 사용방법

그래서 FrameLayout 최초로 보여줄 Fragment를 설정하는 코드는 savedInstanceState가 null인 경우에만 추가해줍니다.

 

class MainActivity : AppCompatActivity() {
    private lateinit var binding: ActivityMainBinding

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)
        
        if (savedInstanceState == null) {
            supportFragmentManager.beginTransaction()
                .add(R.id.frame_layout, SearchFragment())
                .commit()
        }
    }
}

 

Fragment에 초기 값이 필요하다면 add args에 bundle 형태로 전달해줄 수 있습니다.

 

val bundle = bundleOf("query" to "Android")
supportFragmentManager.beginTransaction()
    .add(R.id.frame_layout, SearchFragment::class.java, bundle)
    .commit()

 

 

오해한 개념

Fragment는 FragmentTransaction의 addToBackStack 함수로 backstack에 저장한 경우에만 복원된다고 생각했습니다.

 

 

참고 자료

https://developer.android.com/guide/fragments/create

 

프래그먼트 만들기  |  Android 개발자  |  Android Developers

프래그먼트 만들기 컬렉션을 사용해 정리하기 내 환경설정을 기준으로 콘텐츠를 저장하고 분류하세요. 프래그먼트는 활동 내에서 사용자 인터페이스의 모듈식 부분을 말합니다. 프래그먼트는

developer.android.com

https://developer.android.com/guide/fragments/fragmentmanager#perform

 

프래그먼트 관리자  |  Android 개발자  |  Android Developers

이 페이지는 Cloud Translation API를 통해 번역되었습니다. 프래그먼트 관리자 컬렉션을 사용해 정리하기 내 환경설정을 기준으로 콘텐츠를 저장하고 분류하세요. 참고: Navigation 라이브러리를 사용

developer.android.com