eas*_*ese 14 android dependency-injection kotlin dagger dagger-2
class SlideshowViewModel : ViewModel() {
@Inject lateinit var mediaItemRepository : MediaItemRepository
fun init() {
What goes here?
}
Run Code Online (Sandbox Code Playgroud)
所以我正在尝试学习Dagger2,这样我就可以让我的应用程序更加可测试.问题是,我已经集成了Kotlin并正在研究Android Architectural组件.我知道构造函数注入是优选的,但这是不可能的ViewModel
.相反,我可以使用lateinit
以便注射,但我不知道如何注射.
我是否需要创建一个Component
for SlideshowViewModel
,然后注入它?或者我使用该Application
组件?
gradle这个:
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
kapt {
generateStubs = true
}
dependencies {
compile "com.google.dagger:dagger:2.8"
annotationProcessor "com.google.dagger:dagger-compiler:2.8"
provided 'javax.annotation:jsr250-api:1.0'
compile 'javax.inject:javax.inject:1'
}
Run Code Online (Sandbox Code Playgroud)
应用组件
@ApplicationScope
@Component (modules = PersistenceModule.class)
public interface ApplicationComponent {
void injectBaseApplication(BaseApplication baseApplication);
}
Run Code Online (Sandbox Code Playgroud)
BaseApplication
private static ApplicationComponent component;
@Override
public void onCreate() {
super.onCreate();
component = DaggerApplicationComponent
.builder()
.contextModule(new ContextModule(this))
.build();
component.injectBaseApplication(this);
}
public static ApplicationComponent getComponent() {
return component;
}
Run Code Online (Sandbox Code Playgroud)
您可以为ViewModel启用构造函数注入.您可以查看Google示例,了解如何在Java中执行此操作.(更新:看起来他们将项目转换为Kotlin,因此此URL不再有效)
以下是如何在Kotlin中做类似的事情:
添加ViewModelKey批注:
import android.arch.lifecycle.ViewModel
import java.lang.annotation.Documented
import java.lang.annotation.ElementType
import java.lang.annotation.Retention
import java.lang.annotation.RetentionPolicy
import java.lang.annotation.Target
import dagger.MapKey
import kotlin.reflect.KClass
@Suppress("DEPRECATED_JAVA_ANNOTATION")
@Documented
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@MapKey
internal annotation class ViewModelKey(val value: KClass<out ViewModel>)
Run Code Online (Sandbox Code Playgroud)
添加ViewModelFactory:
import android.arch.lifecycle.ViewModel
import android.arch.lifecycle.ViewModelProvider
import javax.inject.Inject
import javax.inject.Provider
import javax.inject.Singleton
@Singleton
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<out 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)
}
}
}
Run Code Online (Sandbox Code Playgroud)
添加ViewModelModule:
import dagger.Module
import android.arch.lifecycle.ViewModel
import dagger.multibindings.IntoMap
import dagger.Binds
import android.arch.lifecycle.ViewModelProvider
import com.bubelov.coins.ui.viewmodel.EditPlaceViewModel
@Module
abstract class ViewModelModule {
@Binds
@IntoMap
@ViewModelKey(EditPlaceViewModel::class) // PROVIDE YOUR OWN MODELS HERE
internal abstract fun bindEditPlaceViewModel(editPlaceViewModel: EditPlaceViewModel): ViewModel
@Binds
internal abstract fun bindViewModelFactory(factory: ViewModelFactory): ViewModelProvider.Factory
}
Run Code Online (Sandbox Code Playgroud)
在组件中注册ViewModelModule
在您的活动中注入ViewModelProvider.Factory:
@Inject lateinit var modelFactory: ViewModelProvider.Factory
private lateinit var model: EditPlaceViewModel
Run Code Online (Sandbox Code Playgroud)
将modelFactory传递给每个ViewModelProviders.of方法:
model = ViewModelProviders.of(this, modelFactory)[EditPlaceViewModel::class.java]
Run Code Online (Sandbox Code Playgroud)
以下是包含所有必需更改的示例提交:支持视图模型的构造函数注入
假设你有一个Repository
可以被 Dagger 注入的MyViewModel
类和一个依赖于Repository
定义的类:
class Repository @Inject constructor() {
...
}
class MyViewModel @Inject constructor(private val repository: Repository) : ViewModel() {
...
}
现在您可以创建您的ViewModelProvider.Factory
实现:
class MyViewModelFactory @Inject constructor(private val myViewModelProvider: Provider<MyViewModel>) : ViewModelProvider.Factory {
@Suppress("UNCHECKED_CAST")
override fun <T : ViewModel> create(modelClass: Class<T>): T {
return myViewModelProvider.get() as T
}
}
Run Code Online (Sandbox Code Playgroud)
Dagger 设置看起来并不复杂:
@Component(modules = [MyModule::class])
interface MyComponent {
fun inject(activity: MainActivity)
}
@Module
abstract class MyModule {
@Binds
abstract fun bindsViewModelFactory(factory: MyViewModelFactory): ViewModelProvider.Factory
}
这是实际注入发生的活动类(也可能是片段):
class MainActivity : AppCompatActivity() {
@Inject
lateinit var factory: ViewModelProvider.Factory
lateinit var viewModel: MyViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// retrieve the component from application class
val component = MyApplication.getComponent()
component.inject(this)
viewModel = ViewModelProviders.of(this, factory).get(MyViewModel::class.java)
}
}
不。您创建一个组件,在其中声明(使用)您的 viewModel。它通常是一个活动/片段。viewModel 有依赖项(mediaitemrepository),所以你需要一个工厂。像这样的东西:
class MainViewModelFactory (
val repository: IExerciseRepository): ViewModelProvider.Factory {
@Suppress("UNCHECKED_CAST")
override fun <T : ViewModel?> create(p0: Class<T>?): T {
return MainViewModel(repository) as T
}
}
Run Code Online (Sandbox Code Playgroud)
然后是匕首部分(活动模块)
@Provides
@ActivityScope
fun providesViewModelFactory(
exerciseRepos: IExerciseRepository
) = MainViewModelFactory(exerciseRepos)
@Provides
@ActivityScope
fun provideViewModel(
viewModelFactory: MainViewModelFactory
): MainViewModel {
return ViewModelProviders
.of(act, viewModelFactory)
.get(MainViewModel::class.java)
}
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
4915 次 |
最近记录: |