【Android × Kotlin】FragmentFactory を使って、コンストラクタ経由で Fragment に値を渡す
今回は、FragmentFactory を使って、コンストラクタ経由で Fragment に値を渡す方法を解説します。
なお、ここに掲載しているソースコードは以下の環境で動作確認しています。
- Android Studio Chipmunk | 2021.2.1 Patch 1
- JDK 11.0.12
- Android Gradle Plugin 7.2.1
- Kotlin 1.6.21
- Gradle 7.4.2
- androidx.fragment 1.4.1
概要
通常、Fragment のコンストラクタに引数を追加することはできません。コンストラクタに引数を追加すると、Fragment を生成する際に例外が発生するからです。
これは、FragmentManager に設定されている FragmentFactory が Fragment を生成するのですが、デフォルトの FragmentFactory は引数が存在しないコンストラクタを使用して、Fragment を生成しようとするためです。
よって、Fragment のコンストラクタに引数を追加して、その引数ありのコンストラクタで Fragment を生成するためには、FragmentFactory を継承したカスタムの FragmentFactory を作成し、これを FragmentManager に設定する必要があります。
今回は、実際に FragmentFactory を継承してカスタム FragmentFactory を作成しながら、FragmentFactory を使って、コンストラクタ経由で Fragment に値を渡す方法を解説します。
ライブラリのインポート
FragmentFactory を使用するため、アプリの build.gradle ファイルの dependencies
に fragment-ktx
を追加してください。
dependencies {
implementation "androidx.fragment:fragment-ktx:1.4.1"
}
FragmentFactory を使って、Fragment に値を渡す
今回は、以下のようなサービスクラスをコンストラクタ経由で Fragment に渡すコードを作成します。
interface SampleService { fun getText(): String } class SampleServiceImpl : SampleService { override fun getText(): String = "Sample" }
まず、Fragment から作成します。
Fragment ではコンストラクタ経由でさきほどの SampleService
を受け取りたいため、コンストラクタ引数に SampleService
を追加します。
class MainFragment( private val service: SampleService ) : Fragment(R.layout.main_fragment) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) val textView: TextView = view.findViewById(R.id.message) textView.text = service.getText() } }
次に、FragmentFactory を継承したカスタム FragmentFactory を作成します。
FragmentFactory を使って、引数ありのコンストラクタで Fragment を生成する場合、instantiate をオーバーライドします。このメソッドは、Fragment を生成するメソッドです。カスタム FragmentFactory でオーバーライドした instantiate では、引数 className
が該当の Fragment である場合、その Fragment のコンストラクタを呼ぶようにします。そうではない場合、継承元クラスの instantiate を呼ぶようにします。
class CustomFragmentFactory( private val service: SampleService ) : FragmentFactory() { override fun instantiate(classLoader: ClassLoader, className: String) = if (className == MainFragment::class.java.name) { MainFragment(service) } else { super.instantiate(classLoader, className) } }
最後に、Activity を作成します。
Activity では、FragmentManager にさきほどのカスタム FragmentFactory を設定します。なお、このカスタム FragmentFactory の設定は、継承元の onCreate を呼ぶ前に行ってください。
class MainActivity : AppCompatActivity(R.layout.main_activity) { override fun onCreate(savedInstanceState: Bundle?) { supportFragmentManager.fragmentFactory = CustomFragmentFactory(SampleServiceImpl()) super.onCreate(savedInstanceState) } }
以上で、コンストラクタ経由で Fragment に値を渡せるようになります。