如何使用dagger 2创建ViewModel并将存储库注入其中?

ip6*_*696 7 android viewmodel dagger-2

我尝试了解ViewModel.我创建了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();
    }

}
Run Code Online (Sandbox Code Playgroud)

但我不明白两件事:

  1. 我怎么能注入UsersRepository 这个VievModel?当我使用演示者时,我可以用匕首2创建它,如下所示:
@Module
public class PresentersModule {

    @Singleton
    @Provides
    UsersPresenter provideUsersPresenter(UsersRepository usersRepository) {
        return new UsersPresenter(usersRepository);
    }
}
Run Code Online (Sandbox Code Playgroud)

但我怎么能这样做呢ViewModel?像这样?

@Module
public class ViewModelsModule {

    @Singleton
    @Provides
    UsersViewModel provideUsersViewModel(UsersRepository usersRepository) {
        return new UsersViewModel(usersRepository);
    }
}
Run Code Online (Sandbox Code Playgroud)
  1. 如何在片段中获取此ViewModel?有了演示者,我可以这样:

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

Rez*_*adi 12

ViewModel是通过ViewModelProvider使用a ViewModelFactory创建实例创建的.您无法直接注入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);
    }
}
}
Run Code Online (Sandbox Code Playgroud)

然后,您需要一个匕首模块,用于创建视图模型工厂并查看模型本身.

@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);
}
Run Code Online (Sandbox Code Playgroud)

ViewModelKey 文件是这样的

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

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

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);

}
Run Code Online (Sandbox Code Playgroud)

要像浏览器一样向ViewModel注入任何内容,只需使用Constructor Injection.

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


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

    }
}
Run Code Online (Sandbox Code Playgroud)

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

  • 看着这个,我严重质疑这是否与依赖注入有关。调用 get(PlayerViewModel.class) 完全否定了 DI 的目的,即允许可测试性。 (2认同)