Dagger2(android support module)をつかってFragmentにDIする


Dagger2(android support module)をつかってFragmentにDIする方法をまとめていく。

HasSupportFragmentInjectorを実装する

MainActivityにHasSupportFragmentInjectorを継承させ必要な実装をします。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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としてまとめる。

1
2
3
4
5
6
7
@Module
internal abstract class MainModule {

    @ContributesAndroidInjector
    abstract fun contributeMainFragment(): ForecastsFragment

}

MainActivityのSubcomponentにMainModuleを追加する。

1
2
3
4
5
6
@Module
internal abstract class UiModule {

    @ContributesAndroidInjector(modules = [MainModule::class])
    internal abstract fun contributeMainActivity(): MainActivity
}

今後、MainActivityに機能が追加する場合は、MainModuleに依存するモジュールを追加していく。

Fragmenのライフサイクルに合わせてInject

サンプルのコードではonAttachでInjetctをしている。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
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()
    }
}

コード

今回のコードはこちらのPRにまとまっていますので参考になれば嬉しいです。