Dagger2(android support module)をつかってFragmentにDIする
Dagger2(android support module)をつかってFragmentにDIする方法をまとめていく。
HasSupportFragmentInjectorを実装する
MainActivityにHasSupportFragmentInjectorを継承させ必要な実装をします。
class MainActivity : AppCompatActivity(), HasSupportFragmentInjector { @Inject lateinit var androidInjector: DispatchingAndroidInjector<Fragment> override fun supportFragmentInjector() = androidInjector override fun onCreate(savedInstanceState: Bundle?) { AndroidInjection.inject(this) super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) setContentFragment(R.id.mainLayout) } private fun setContentFragment(containerViewId: Int) { supportFragmentManager.let { manager -> manager.findFragmentById(containerViewId)?.let { return } ForecastsFragment.newInstance().apply { manager?.beginTransaction()?.add(containerViewId, this)?.commit() } } } }
Fragmenのモジュールをまとめる
Fragmentで管理するモジュールを MainModule
としてまとめる。
@Module internal abstract class MainModule { @ContributesAndroidInjector abstract fun contributeMainFragment(): ForecastsFragment }
MainActivityのSubcomponentにMainModuleを追加する。
@Module internal abstract class UiModule { @ContributesAndroidInjector(modules = [MainModule::class]) internal abstract fun contributeMainActivity(): MainActivity }
今後、MainActivityに機能が追加する場合は、MainModuleに依存するモジュールを追加していく。
Fragmenのライフサイクルに合わせてInject
サンプルのコードではonAttach
でInjetctをしている。
class ForecastsFragment : Fragment() { @Inject lateinit var openWeatherMapRepository: OpenWeatherMapRepository private var listView: ListView by Delegates.notNull() override fun onAttach(context: Context?) { AndroidSupportInjection.inject(this) super.onAttach(context) } override fun onCreateView(inflater: LayoutInflater?, container: ViewGroup?, savedInstanceState: Bundle?): View? { val view = inflater?.inflate(R.layout.forcasts_fragment, container, false) ?: return null listView = view.findViewById<ListView>(R.id.list_view) return view } override fun onActivityCreated(savedInstanceState: Bundle?) { super.onActivityCreated(savedInstanceState) openWeatherMapRepository.findForecastByDaily() .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe { forecasts -> listView.adapter = ArrayAdapter<String>(activity, android.R.layout.simple_list_item_1, forecasts.list.map { "%s - %s %s/%s".format( DateUtils.formatDateTime(activity, it.dt * 1000L, FORMAT_NO_YEAR), it.weather.get(0).main, it.temp.min, it.temp.max) }) } } companion object { fun newInstance() = ForecastsFragment() } }
- Fragmentの理解は公式のドキュメントが分かりやすい。
- Fragmentを部品と捉えてタブレットとハンドセットで異なるレイアウトでも部品(Fragment)を組み合わせることで柔軟に対応することができるし部品の再利用も容易にできる。
コード
今回のコードはこちらのPRにまとまっていますので参考になれば嬉しいです。