본문 바로가기
안드로이드/Fragment

Fragment 생성자 조건

by 김어찐 2022. 11. 1.
728x90

Fragment 생성시 newInstance() 사용하는 이유

 

1. 프래그먼트 재성성(화면 회전과 같은)시 빈 생성자가 있어야 한다

2. 재생성시 받아온 데이터를 유지하기 위해서 사용한다.

 

자주사용하는코드

companion object {

    private const val ARG_PARAM1 = "param1"
    private const val ARG_PARAM2 = "param2"

    @JvmStatic
    fun newInstance(param1: String, param2: String) =
        MainFragment().apply {
            arguments = Bundle().apply {
                putString(ARG_PARAM1, param1)
                putString(ARG_PARAM2, param2)
            }
        }
}

 

newInstance()방식은 빈생자를 만들고 bundle에 데이터를 넣어 처리해 주고 있다.

이렇게 함으로써 화면 회전과 같은 재사용이 되었을 때 받아온 데이터를 유지하며 화면에 보여줄 수 있다.

# 빈생성자 없으면 에러 발생

 

AndroidX부터는 다른 방식으로 초기화 해줘도 가능

AndroidX로 업데이트 되면서 기존에 사용하던 Fragment.instantiate()는 deprecated 되었다.

 

구글에서는 위 방식이 아닌 이제 FragmentFactory의 instantiate를 사용해 구현하라고 했다.

윕 방법을 사용하는 이유는 기존에는 프래그먼트에 빈 생성자가 없다면 구성 변경 및 앱의 프로세스 재성성과 같은 특정 상황에서 시스템은 프래그먼트를 초기화 하지 못했다.

이점을 해결하기 위해 FragmentFactory를 사용하게 되었고 Fragment에 필요한 인수 및 종속성을 제고하여 시스템이 Fragment를 더욱 잘 초기화하는데 도움을 준다.

 

AndroidX에서 인자가 있는 프래그먼트 생성 방법

1. 빈생성자 없이 인자가 있는 생성자를 만들어 준다.

class MainFragment(private val param1: String, private val param2: String) : Fragment() {
    //...

}

2. FragmentFactory의 instantiate를 구현해 준다.

class MainFragmentFactoryImpl: FragmentFactory() {
    override fun instantiate(classLoader: ClassLoader, className: String): Fragment {
        return when (className) {
            MainFragment::class.java.name -> MainFragment("black","jin")
            else -> super.instantiate(classLoader, className)
        }
    }
}

 

3. MainActivity에서 다음과 같이 구현한다.

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        supportFragmentManager.fragmentFactory = MainFragmentFactoryImpl()
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val fragment = supportFragmentManager.fragmentFactory.instantiate(classLoader, MainFragment::class.java.name)
        supportFragmentManager.beginTransaction()
            .replace(R.id.container_fragment, fragment)
            .commitNow()
    }

 

위 방법을 사용하면 Fragment.java에 있던 instatiate를 사용하지 않고 우리가 정의한 FragmentFactory의 instantiate 사용해 초기화를 하게된다.

 

여기서 중요한점

supportFragmentManager.fragmentFactory = FragmentFactoryImpl()

위 함수를 Activity의 onCreate보다 먼저 선언해 주어야 한다는 것이다

이렇게 하면 빈 생성자를 굳이 생성할 필요 없으며 bundle에 데이터를 넣지 않아도 재성성 상황에서 데이터가 보존된다.

 

 

 

FragmentFactory 꼭 필요한가?

그렇지 않다. 기존 방식대로 사용해도 무방하다. 다만 인자가 있는 생성자를 사용할 시 반드시 빈 생성자 프래그먼트를 만들어 주어야 한다.

 

Koin을 사용한 Fragment 초기화

FragmentFactory는 생성자를 주입하는 패턴과 비슷하다. 이에 안드로이드 의존성 주입 라이브러리 중 하나인 Koin에서는 위 방법을 지원해준다.

 startKoin {
    // setup a KoinFragmentFactory instance
    fragmentFactory()

    modules(...)
}

 

 

참고

https://black-jin0427.tistory.com/250

 

[Android, FragmentFactory] framgnet에서 newInstance() 쓰지 말라고?

안녕하세요. 블랙진입니다. 우리는 프래그먼트를 인자와 함께 생성할 때 newInstance()를 사용하곤 합니다. 왜 그럴까요? 흔히 알고 있는 두가지 이유가 있을 겁니다. 1. 프래그먼트 재생성(화면 회

black-jin0427.tistory.com

 

728x90