如何创建视图模型并使用匕首 2 向其注入存储库?



我试着理解ViewModel。我创建视图模型:

public class UsersViewModel extends ViewModel {
private final UsersRepository usersRepository;
public UsersViewModel(UsersRepository usersRepository) {
this.usersRepository = usersRepository;
}
public LiveData<List<User>> loadAll() {
return usersRepository.getAll();
}
}

但我不明白两件事:

  1. 我怎样才能UsersRepository注入这个VievModel?当我使用演示器时,我可以使用dagger 2 创建它,如下所示:
@Module
public class PresentersModule {
@Singleton
@Provides
UsersPresenter provideUsersPresenter(UsersRepository usersRepository) {
return new UsersPresenter(usersRepository);
}
}

但是我该怎么用ViewModel呢?喜欢这个?

@Module
public class ViewModelsModule {
@Singleton
@Provides
UsersViewModel provideUsersViewModel(UsersRepository usersRepository) {
return new UsersViewModel(usersRepository);
}
}
  1. 如何获取此视图模型的片段?与演示者一起,我可以这样做:

    presenter = MyApplication.get((.getAppComponent((.getUsersPresenter((;

ViewModel是通过使用ViewModelFactory创建实例的ViewModelProvider创建的。您不能直接注入 ViewModels,而应使用如下所示的自定义工厂

@Singleton
public class DaggerViewModelFactory implements ViewModelProvider.Factory {
private final Map<Class<? extends ViewModel>, Provider<ViewModel>> creators;
@Inject
public DaggerViewModelFactory(Map<Class<? extends ViewModel>, Provider<ViewModel>> creators) {
this.creators = creators;
}
@SuppressWarnings("unchecked")
@Override
public <T extends ViewModel> T create(Class<T> modelClass) {
Provider<? extends ViewModel> creator = creators.get(modelClass);
if (creator == null) {
for (Map.Entry<Class<? extends ViewModel>, Provider<ViewModel>> entry : creators.entrySet()) {
if (modelClass.isAssignableFrom(entry.getKey())) {
creator = entry.getValue();
break;
}
}
}
if (creator == null) {
throw new IllegalArgumentException("unknown model class " + modelClass);
}
try {
return (T) creator.get();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}

然后,您需要一个用于创建视图模型工厂和视图模型本身的dagger模块。

@Module
abstract class ViewModelModule {
@Binds
abstract ViewModelProvider.Factory bindViewModelFactory(DaggerViewModelFactory factory);
@Binds
@IntoMap
@ViewModelKey(VideoListViewModel.class)
abstract ViewModel provideVideoListViewModel(VideoListViewModel videoListViewModel);
@Binds
@IntoMap
@ViewModelKey(PlayerViewModel.class)
abstract ViewModel providePlayerViewModel(PlayerViewModel playerViewModel);
@Binds
@IntoMap
@ViewModelKey(PlaylistViewModel.class)
abstract ViewModel providePlaylistViewModel(PlaylistViewModel playlistViewModel);
@Binds
@IntoMap
@ViewModelKey(PlaylistDetailViewModel.class)
abstract ViewModel providePlaylistDetailViewModel(PlaylistDetailViewModel playlistDetailViewModel);
}

ViewModelKey文件是这样的

@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@MapKey
@interface ViewModelKey {
Class<? extends ViewModel> value();
}

现在,要在活动或片段中获取视图模型,只需注入视图模型工厂,然后使用该工厂创建视图模型实例

public class PlayerActivity extends BaseActivity {
@Inject DaggerViewModelFactory viewModelFactory;
PlayerViewModel viewModel;
@Override
protected void onCreate(Bundle savedInstanceState) {
AndroidInjection.inject(this);
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_player);
viewModel = ViewModelProviders.of(this,viewModelFactory).get(PlayerViewModel.class);
}

要将任何内容注入到您的 ViewModel(如存储库(,只需使用构造函数注入即可。

public class PlayerViewModel extends ViewModel {
private VideoRepository videoRepository;
private AudioManager audioManager;

@Inject
public PlayerViewModel(VideoRepository videoRepository, AudioManager audioManager) {
this.videoRepository = videoRepository;
this.audioManager = audioManager;
}
}

https://github.com/alzahm/VideoPlayer 从这里查看完整的工作示例,我也从谷歌样本中学到了许多dagger的东西,你也可以看看它们。

Dagger2 要求您创建ViewModelModule并绑定到您的ViewModels

我知道你在问Dagger2,但如果你正在开始一个新项目,也许你可以看看Koin它提供了一个轻量级的注入。

我已经在我的一些生产应用程序中使用了它,它使用较少的代码行就可以正常工作。

你可以在你的模块中声明,比如

viewModel { MyViewModel(get()) }

然后在你的活动/片段/类(你需要扩展KoinComponent(,只需写

val myViewModel : MyViewModel by viewModel()

它将处理创建本身。

欲了解更多信息,可以参考

https://insert-koin.io/

https://start.insert-koin.io/#/getting-started/koin-for-android?id=android-viewmodel

我写了一个库,它应该使它更直接、更干净,不需要多重绑定或工厂样板,同时还能够在运行时进一步参数化ViewModel: https://github.com/radutopor/ViewModelFactory

@ViewModelFactory
class UserViewModel(@Provided repository: Repository, userId: Int) : ViewModel() {
val greeting = MutableLiveData<String>()
init {
val user = repository.getUser(userId)
greeting.value = "Hello, $user.name"
}    
}

在视图中:

class UserActivity : AppCompatActivity() {
@Inject
lateinit var userViewModelFactory2: UserViewModelFactory2
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_user)
appComponent.inject(this)
val userId = intent.getIntExtra("USER_ID", -1)
val viewModel = ViewModelProviders.of(this, userViewModelFactory2.create(userId))
.get(UserViewModel::class.java)
viewModel.greeting.observe(this, Observer { greetingText ->
greetingTextView.text = greetingText
})
}
}

此解决方案允许您在没有工厂的情况下将依赖项注入到 ViewModels 和 Workers 中。相反,它使用静态方法。

将图形注入类

此行可以在 init 块或 onCreate 方法中使用(底部的示例视图模型(

Injector.getComponent().inject(this)

基本应用程序

class BaseApplication : Application() {

lateinit var applicationComponent: ApplicationComponent

override fun onCreate() {
super.onCreate()
INSTANCE = this
applicationComponent = DaggerApplicationComponent
.builder()
//Add your modules
.build()
}

companion object {
private var INSTANCE: BaseApplication? = null

@JvmStatic
fun get(): BaseApplication= INSTANCE!!
}
}

注射器

class Injector private constructor() {
companion object {
@JvmStatic
fun getComponent(): ApplicationComponent = BaseApplication.get().applicationComponent
}
}

就是这样!

像往常一样在应用程序组件中请求注入

应用程序组件

Singleton
@Component(modules = [add your modules])
interface ApplicationComponent {
fun inject(someViewModel: SomeViewModel)
}

视图模型

class SomeViewModel : ViewModel(){
@Inject
lateinit var someClass: SomeClass //In your case, userRepository: UserRepository
init{
Injector.getComponent().inject(this)
}
}

最新更新