Skip to content

Instantly share code, notes, and snippets.

@marukami
Created November 15, 2018 03:52
Show Gist options
  • Save marukami/3024dd7ae399a4a33df3041a9af84401 to your computer and use it in GitHub Desktop.
Save marukami/3024dd7ae399a4a33df3041a9af84401 to your computer and use it in GitHub Desktop.
MvRx Dagger Boilerplate
package au.tilbrook.mvrx.dagger
import androidx.fragment.app.FragmentActivity
import androidx.lifecycle.ViewModel
import com.airbnb.mvrx.BaseMvRxViewModel
import com.airbnb.mvrx.MvRxState
import com.airbnb.mvrx.MvRxViewModelFactory
import javax.inject.Provider
interface ViewModelFactory {
fun create(state: MvRxState): ViewModel
}
interface HasDaggerMvRxViewModelFactory {
val factory: DaggerMvRxViewModelFactory
}
class DaggerMvRxViewModelFactory(
private val creators: MutableMap<Class<out ViewModelFactory>, Provider<ViewModelFactory>>
) {
fun <T : ViewModelFactory, R : ViewModel> create(
modelClass: Class<T>,
state: MvRxState
): R {
var creator: Provider<out ViewModelFactory>? = 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 {
@Suppress("UNCHECKED_CAST")
return (creator.get() as T).create(state) as R
} catch (e: Exception) {
throw RuntimeException(e)
}
}
}
inline fun <reified F : ViewModelFactory, VM : ViewModel> FragmentActivity.daggerCreate(
factory: Class<F>,
state: MvRxState
): VM =
let { it as HasDaggerMvRxViewModelFactory }
.factory
.create(modelClass = factory, state = state)
class HostActivity :
AppCompatActivity(),
HasDaggerMvRxViewModelFactory {
@Inject lateinit var mvRxViewModelFactory: DaggerMvRxViewModelFactory
override val factory: DaggerMvRxViewModelFactory
get() = mvRxViewModelFactory
}
abstract class MvRxViewModel<S : MvRxState>(initialState: S) : BaseMvRxViewModel<S>(
initialState = initialState,
debugMode = BuildConfig.DEBUG
) {
val state: S = initialState
}
class MyViewModel @AssistedInject constructor(
@Assisted state: MvRxState,
private val api: Api
) : MvRxViewModel<MyViewModelState>(state as MyViewModelState) {
@AssistedInject.Factory
interface Factory : ViewModelFactory {
override fun create(state: MvRxState): MyViewModel
}
companion object : MvRxViewModelFactory<MyViewModelState> {
@JvmStatic override fun create(
activity: FragmentActivity,
state: MyViewModelState
): BaseMvRxViewModel<MyViewModelState> =
activity.daggerCreate(
factory = MyViewModel.Factory::class.java,
state = state
)
}
}
@AssistedModule
@Module(
includes = [
BindsViewModelFactoryModule::class,
AssistedInject_ViewModelFactoryModule::class
]
)
object ViewModelFactoryModule {
@JvmStatic
@Provides
fun providesDaggerMvRxViewModelFactory(
factories: MutableMap<Class<out ViewModelFactory>, Provider<ViewModelFactory>>
): DaggerMvRxViewModelFactory =
DaggerMvRxViewModelFactory(factories)
}
@Module
abstract class BindsViewModelFactoryModule {
@Binds
@IntoMap
@ViewModelFactoryKey(MyViewModel.Factory::class)
abstract fun bindsMyViewModelFactory(
factory: MyViewModel.Factory
): ViewModelFactory
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment