Master of Dagger の改定版にも入れる予定です。ただいま鋭意執筆中です。もう少々お待ちください。
ViewModelFactory と同じような感じで FragmentFactory および Fragment の生成をまかせることができます。
オブジェクトグラフに MyApi があるとします。
- @Module
- object AppModule {
-
- @Provides
- fun provideMyApi(): MyApi {
- ...
- }
- }
@Module
object AppModule {
@Provides
fun provideMyApi(): MyApi {
...
}
}
これを引数にとる Fragment があります。Dagger に生成をまかせたいのでコンストラクタに @Inject をつけます。
- class MainFragment @Inject constructor(private val api: MyApi) : Fragment() {
-
- ...
- }
class MainFragment @Inject constructor(private val api: MyApi) : Fragment() {
...
}
Fragment の Map Multibindings 用の MapKey を用意します。
- @Target(
- AnnotationTarget.FUNCTION,
- AnnotationTarget.PROPERTY_GETTER,
- AnnotationTarget.PROPERTY_SETTER
- )
- @Retention(AnnotationRetention.RUNTIME)
- @MapKey
- annotation class FragmentKey(val value: KClass<out Fragment>)
@Target(
AnnotationTarget.FUNCTION,
AnnotationTarget.PROPERTY_GETTER,
AnnotationTarget.PROPERTY_SETTER
)
@Retention(AnnotationRetention.RUNTIME)
@MapKey
annotation class FragmentKey(val value: KClass<out Fragment>)
用意した MapKey を使って MainFragment を Multibindings に追加します。
- @Module
- interface FragmentModule {
-
- @Binds
- @IntoMap
- @FragmentKey(MainFragment::class)
- fun bindMainFragment(fragment: MainFragment): Fragment
- }
@Module
interface FragmentModule {
@Binds
@IntoMap
@FragmentKey(MainFragment::class)
fun bindMainFragment(fragment: MainFragment): Fragment
}
Fragment の Multibindings を引数に取る FragmentFactory を用意します。
- class MyFragmentFactory @Inject constructor(
- private val providers: Map<Class<out Fragment>, @JvmSuppressWildcards Provider<Fragment>>
- ) : FragmentFactory() {
-
- override fun instantiate(classLoader: ClassLoader, className: String): Fragment {
- val found = providers.entries.find { className == it.key.name }
- ?: throw IllegalArgumentException("unknown model class $className")
-
- val provider = found.value
-
- try {
- @Suppress("UNCHECKED_CAST")
- return provider.get()
- } catch (e: Exception) {
- return super.instantiate(classLoader, className)
- }
- }
- }
class MyFragmentFactory @Inject constructor(
private val providers: Map<Class<out Fragment>, @JvmSuppressWildcards Provider<Fragment>>
) : FragmentFactory() {
override fun instantiate(classLoader: ClassLoader, className: String): Fragment {
val found = providers.entries.find { className == it.key.name }
?: throw IllegalArgumentException("unknown model class $className")
val provider = found.value
try {
@Suppress("UNCHECKED_CAST")
return provider.get()
} catch (e: Exception) {
return super.instantiate(classLoader, className)
}
}
}
用意した MyFragmentFactory を取得するためのメソッドを Component に用意します。
- @Component(modules = [AppModule::class, FragmentModule::class])
- interface AppComponent {
-
- fun fragmentFactory(): MyFragmentFactory
- }
-
- class MyApplication : Application() {
-
- lateinit var appComponent: AppComponent
-
- override fun onCreate() {
- super.onCreate()
-
- appComponent = DaggerAppComponent.builder()
- .build()
- }
- }
@Component(modules = [AppModule::class, FragmentModule::class])
interface AppComponent {
fun fragmentFactory(): MyFragmentFactory
}
class MyApplication : Application() {
lateinit var appComponent: AppComponent
override fun onCreate() {
super.onCreate()
appComponent = DaggerAppComponent.builder()
.build()
}
}
supportFragmentManager.fragmentFactory に Component から取得した MyFragmentFactory をセットします。
- class MainActivity : AppCompatActivity() {
-
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
-
- supportFragmentManager.fragmentFactory = (application as MyApplication).appComponent
- .fragmentFactory()
-
- setContentView(R.layout.activity_main)
- }
- }
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
supportFragmentManager.fragmentFactory = (application as MyApplication).appComponent
.fragmentFactory()
setContentView(R.layout.activity_main)
}
}
activity_main.xml
- <?xml version="1.0" encoding="utf-8"?>
- <fragment xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/mainFragment"
- android:name="net.yanzm.sample.MainFragment"
- android:layout_width="match_parent"
- android:layout_height="match_parent" />
<?xml version="1.0" encoding="utf-8"?>
<fragment xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/mainFragment"
android:name="net.yanzm.sample.MainFragment"
android:layout_width="match_parent"
android:layout_height="match_parent" />
0 件のコメント:
コメントを投稿