Dagger2 + Retrofit2 + Moshi + Kotlin を使って通信するまで
こちらの続きで、これに Fragment + ViewModel を追加していきたいと思います。
フラグメント(with ViewModel)
Fragment を実装
Fragment の Module を作成する。
@Module
abstract class FragmentModule {
@ContributesAndroidInjector
abstract fun contributeMainFragment(): MainFragment
}
Component にモジュールを追加する。
@Singleton
@Component(modules = [AndroidSupportInjectionModule::class, ActivityModule::class, FragmentModule::class, RetrofitModule::class])
Fragment を DaggerFragment に変更する。
class MainFragment : DaggerFragment() {
レイアウトを修正する。
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<FrameLayout
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent">
</FrameLayout>
</android.support.constraint.ConstraintLayout>
Activity から Fragment を呼び出す。
class MainActivity : DaggerAppCompatActivity() {
@Inject
lateinit var github: GitHubService
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
if (savedInstanceState == null) {
supportFragmentManager.beginTransaction()
.replace(R.id.container, MainFragment.newInstance())
.commitNow()
}
}
...
ViewModel を実装
annotation を作成する。
@Target(AnnotationTarget.FUNCTION)
@Retention(AnnotationRetention.RUNTIME)
@MapKey
annotation class ViewModelKey(val value: KClass<out ViewModel>)
ViewModelProvider.Factory を作成する。
class ViewModelFactory @Inject constructor(
private val creators: Map<Class<out ViewModel>, @JvmSuppressWildcards Provider<ViewModel>>
) : ViewModelProvider.Factory {
@Suppress("UNCHECKED_CAST")
override fun <T : ViewModel?> create(modelClass: Class<T>): T {
var creator: Provider<ViewModel>? = creators[modelClass]
if (creator == null) {
for ((key, value) in creators) {
if (modelClass.isAssignableFrom(key)) {
creator = value
break
}
}
}
if (creator == null) throw IllegalArgumentException("unknown model class $modelClass")
try {
return creator.get() as T
} catch (e: Exception) {
throw RuntimeException(e)
}
}
}
ViewModel の Module を作成する。
@Module
abstract class ViewModelModule {
@Binds
internal abstract fun bindViewModelFactory(factory: ViewModelFactory): ViewModelProvider.Factory
@Binds
@IntoMap
@ViewModelKey(MainViewModel::class)
abstract fun bindMainViewModel(mainViewModel: MainViewModel): ViewModel
}
Component にモジュールを追加する。
@Singleton
@Component(modules = [AndroidSupportInjectionModule::class, ActivityModule::class, FragmentModule::class, ViewModelModule::class, RetrofitModule::class])
依存性の注入をする。
Fragment を下記の内容で修正する。
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
viewModel = ViewModelProviders.of(this).get(MainViewModel::class.java)
↓
class MainFragment : DaggerFragment() {
@Inject
lateinit var viewModelFactory: ViewModelFactory
...
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
viewModel = ViewModelProviders.of(this, viewModelFactory).get(MainViewModel::class.java)
ViewModel を修正する。
Dagger2 + Retrofit2 + Moshi + Kotlin を使って通信するまで
で、Activity に実装した処理を ViewModel に実装することで、処理を分離することが可能です。
class MainViewModel @Inject constructor(private val service: GitHubService) : ViewModel() {
fun getUser() {
val userCall: Call<User> = service.getUser("xxxx")
userCall.enqueue(object : Callback<User> {
override fun onFailure(call: Call<User>, t: Throwable) {
}
override fun onResponse(call: Call<User>, response: Response<User>) {
if (response.isSuccessful) {
val user: User? = response.body()
}
}
})
}
}
getUser() を呼び出す。
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
viewModel = ViewModelProviders.of(this, viewModelFactory).get(MainViewModel::class.java)
viewModel.getUser()
}
Activity が、すっきりしました。
class MainActivity : DaggerAppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
if (savedInstanceState == null) {
supportFragmentManager.beginTransaction()
.replace(R.id.container, MainFragment.newInstance())
.commitNow()
}
}
}
本来は、Fragment + ViewModel 含めて記事にしたかったのですが、どうしても膨大になるので、分けて記載しました。
まだ、Dagger2 関連で記事に出来ることがありますので、時間がありましたら、記事にしていきたいと思います。