안드로이드 개발에서 Fragment
는 화면 구성 요소를 분리하고 재사용성을 높이는 데 중요한 역할을 합니다. 일반적으로 Fragment
는 기본 생성자를 사용해야 하지만 개발 과정에서 데이터를 프래그먼트로 전달하기 위해 매개변수가 있는 생성자를 사용하는 경우가 종종 있습니다.
하지만 매개변수가 있는 생성자를 사용하면 구성 변경(Configuration Change)
또는 시스템 재생성 시 문제가 발생할 수 있습니다. 이 글에서는 FragmentFactory
를 활용해 이러한 문제를 해결하고 안정적으로 매개변수가 있는 생성자를 사용하는 방법 입니다.
안드로이드 시스템의 기본 동작:
InstantiationException
이 발생합니다.에러 로그
java.lang.RuntimeException: Unable to start activity ComponentInfo
Caused by: androidx.fragment.app.Fragment$InstantiationException: could not find Fragment constructor
안드로이드 시스템은 구성 변경(Configuration Changes)
발생 시 Fragment를 재생성하는데, 이때 반드시 파라미터가 없는 기본 생성자를 필요로 합니다. 하지만 현재 구현에는 파라미터가 있는 생성자만 존재하여 시스템이 Fragment를 재생성하지 못하는 상황입니다.
안드로이드 개발자 페이지에도 해당 문서에 확인 하면 이유가 나와있습니다.
밑에 글이 해당하는 내용의 이유
https://developer.android.com/reference/android/app/Fragment
All subclasses of Fragment must include a public no-argument constructor. The framework will often re-instantiate a fragment class when needed, in particular during state restore, and needs to be able to find this constructor to instantiate it. If the no-argument constructor is not available, a runtime exception will occur in some cases during state restore.
FragmentFactory
는 프래그먼트 생성 과정을 커스터마이징할 수 있는 클래스입니다.class HomeFragment(private val message: String) : Fragment() {
// 에러 발생: 기본 생성자가 없으므로 시스템 재생성 불가능
}
class HomeFragmentFactory(private val message: String) : FragmentFactory() {
override fun instantiate(classLoader: ClassLoader, className: String): Fragment {
return when (className) {
HomeFragment::class.java.name -> HomeFragment(message)
else -> super.instantiate(classLoader, className)
}
}
}
class HomeFragment(private val message: String) : Fragment() {
private lateinit var binding: FragmentHomeBinding
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
binding = FragmentHomeBinding.inflate(inflater, container, false)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
// 메시지 표시
binding.textView.text = message
}
}
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
supportFragmentManager.fragmentFactory = HomeFragmentFactory("Test")
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
}
}
항목 | Bundle 사용 방식 | FragmentFactory 방식 |
---|---|---|
데이터 전달 | arguments 를 사용해 직렬화 데이터 전달 | 생성자를 통해 직렬화되지 않은 데이터 전달 가능 |
구성 변경 처리 | 상태 저장 및 복원이 필요 | 생성자를 통한 데이터 전달로 상태 복원 가능 |
의존성 주입 | 직접 구현 필요 | 쉽게 구현 가능 |
사용 사례 | 단순 데이터 전달 | 복잡한 데이터 또는 의존성 전달 |
매개변수 생성자 지원:
유연한 데이터 전달:
테스트 용이성:
복잡성 증가:
FragmentFactory
를 추가로 작성해야 하므로 코드가 약간 복잡해질 수 있습니다.기존 코드와의 호환성 문제:
FragmentFactory
를 사용하면 안드로이드 시스템의 기본 생성자 요구 사항을 우회하여 매개변수를 가진 생성자를 안전하게 사용할 수 있다.
이는 구성 변경 및 시스템 재생성 시 발생할 수 있는 크래시 문제를 효과적으로 해결합니다.
언제 사용할까?
arguments
를 사용하는 것이 더 간단하고 적합할 수 있습니다.FragmentFactory
를 사용하는 것이 강력한 대안이 된다고 한다.깃허브 : https://github.com/GEUN-TAE-KIM/Constructors_With_FragmentFactory_Sample
참고
https://developer.android.com/reference/android/app/Fragment
https://developer.android.com/guide/topics/resources/runtime-changes?hl=ko
안녕하세요! 😊
글 정말 잘 읽어봤어요! FragmentFactory를 이용해서 매개변수가 있는 생성자를 안전하게 사용하는 방법을 깔끔하게 정리해주셨네요! 특히 문제 정의부터 해결책까지 단계별로 설명해주셔서 이해하기 쉬웠어요. 👏👏
하지만 몇 가지 생각해볼 부분이 있어서 조금만 피드백 드릴게요! 🙋♂️
코드 예제에 대한 추가 설명 📝
코드 블록 사이사이에 간단한 설명이나 주석이 있으면 독자들이 이해하기 더 쉬울 것 같아요. 예를 들어, 각 코드가 어떤 역할을 하는지, 왜 필요한지에 대한 부가 설명이 있으면 좋을 것 같아요. 😊
FragmentFactory 사용의 단점에 대한 구체적인 예시 ⚠️
단점 부분에서 "기존 코드와의 호환성 문제"를 언급하셨는데, 구체적으로 어떤 문제가 발생할 수 있는지 예시를 들어주시면 더 이해하기 쉬울 것 같아요. 예를 들어, 기존에
arguments
를 통해 데이터를 전달하던 방식과 FragmentFactory를 사용하는 방식이 혼용될 때 발생할 수 있는 문제점 등을 설명해주시면 좋을 것 같아요. 🤔결론 부분의 보완 🔍
"언제 사용할까?" 부분에서 조금 더 구체적인 사례를 들어주시면 좋을 것 같아요. 예를 들어, 의존성 주입이 필요한 경우, 복잡한 객체를 전달해야 하는 경우, 테스트를 용이하게 하기 위해 등 구체적인 상황을 제시하면 독자들이 실제로 적용할 때 큰 도움이 될 것 같아요. 😊
참고 자료의 활용 📚
참고 자료를 링크해주셨는데, 해당 자료들을 어떻게 활용하면 좋을지에 대한 간단한 설명이 있으면 독자들에게 도움이 될 것 같아요. 예를 들어, "더 자세한 내용은 이 링크를 참고하세요!" 같은 식으로요. 👍
전체적으로 정말 유익한 글이었고, 많은 도움이 되었어요! 앞으로도 좋은 글 많이 부탁드릴게요! 감사합니다! 🙇♂️💕