【问题标题】:Dagger 2 multiple RepositoriesDagger 2 多个存储库
【发布时间】:2018-09-17 09:47:52
【问题描述】:

所以我是 Dagger 2 依赖注入的新手。我创建了一个自定义 ViewModelFactory 类,它返回我的 ViewModel。

@Singleton
public class CustomViewModelFactory implements ViewModelProvider.Factory {
    private final MyCatchesRepository repository;

    @Inject
    public CustomViewModelFactory(MyCatchesRepository repository) {
        this.repository = repository;
    }

    @NonNull
    @Override
    @SuppressWarnings("unchecked")
    public <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
        if (modelClass.isAssignableFrom(MyCatchViewModel.class)) {
            return (T) new MyCatchViewModel(repository);
        } else {
            throw new IllegalArgumentException("ViewModel Not Found");
        }
    }
}

CustomViewModel 在构造函数中采用MyCatchesRepository,然后创建MyCatchViewModel。 我怎样才能改变这个类,以便我可以使用这个 ViewModelFactory 来创建具有不同构造函数参数(存储库)的不同 ViewModel

这是创建 CustomViewModelFactory 的模块

@Module
public class RoomModule {

    private final MyDatabase myDatabase;

    public RoomModule(Application application) {
        this.myDatabase = Room.databaseBuilder(application,
                            MyDatabase.class, AppConstants.DATABASE_NAME)
                            .build();
    }

    @Provides
    @Singleton
    MyCatchesRepository provideCatchesRepository(MyCatchDao myCatchDao) {
        return new MyCatchesRepository(myCatchDao);
    }

    @Provides
    @Singleton
    MyCatchDao providesCatchDao(MyDatabase myDatabase) {
        return myDatabase.myCatchDao();
    }


    @Provides
    @Singleton
    LuresRepository provideLureRepository(LureDao lureDao) {
        return new LuresRepository(lureDao);
    }

    @Provides
    @Singleton
    LureDao provideLureDao(MyDatabase myDatabase) {
        return myDatabase.lureDao();
    }

    @Provides
    @Singleton
    MyDatabase provideDatabase(Application application) {
        return myDatabase;
    }

    @Provides
    @Singleton
    ViewModelProvider.Factory provideCatchesViewModelFactory(MyCatchesRepository catchesRepository) {
        return new CustomViewModelFactory(catchesRepository);
    }
}

视图模型模块

@Module
public abstract class ViewModelModule {

    @Binds
    @IntoMap
    @ViewModelKey(MyCatchViewModel.class)
    abstract ViewModel myCatchViewModel(MyCatchViewModel myCatchViewModel);

    @Binds
    @IntoMap
    @ViewModelKey(FishingSpotViewModel.class)
    abstract ViewModel fishingSpotViewModel(FishingSpotViewModel fishingSpotViewModel);

    @Binds
    abstract ViewModelProvider.Factory bindCustomViewModelFactory(CustomViewModelFactory customViewModelFactory);

}

【问题讨论】:

    标签: dependency-injection dagger-2 android-mvvm


    【解决方案1】:

    Google 团队在架构组件示例中提出的方法是使用自定义注解,以便通过 dagger 提供 ViewModel 类。

    在 Java 中,注解如下所示。

    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    import androidx.lifecycle.ViewModel;
    import dagger.MapKey;
    
    @Target(ElementType.METHOD)
    @Retention(RetentionPolicy.RUNTIME)
    @MapKey
    @interface ViewModelKey {
        Class<? extends ViewModel> value();
    }
    

    这使用来自 Dagger 的 MapKey,其中任何带注释的 ViewModel 都将组合成一个 Map,然后可以在您的 ViewModelFactory 中使用。

    在 Google 示例中,ViewModelFactory 如下所示,使用构造函数注入可以访问 ViewModel 提供者的映射。

    public class ViewModelFactory implements ViewModelProvider.Factory {
    
        private final Map<Class<? extends ViewModel>, Provider<ViewModel>> viewModels;
    
        @Inject
        public ViewModelFactory(Map<Class<? extends ViewModel>, Provider<ViewModel>> viewModels) {
            this.viewModels = viewModels;
        }
    
        @NonNull
        @Override
        public <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
            Provider<ViewModel> viewModelProvider = viewModels.get(modelClass);
    
            if (viewModelProvider == null) {
                throw new IllegalArgumentException("model class " + modelClass + " not found");
            }
    
            //noinspection unchecked
            return (T) viewModelProvider.get();
        }
    }
    

    在您的示例中,您最终会得到以下内容以提供 MyCatchViewModel。然后可以按照相同的模式提供其他 ViewModel。

    @Module
    public abstract class ViewModelModule {
        @Binds
        @IntoMap
        @ViewModelKey(MyCatchViewModel.class)
        abstract ViewModel myCatchViewModel(MyCatchViewModel myCatchViewModel);
    }
    

    有关完整示例,您可以查看 Google 的 GithubBrowserSample 示例。 https://github.com/googlesamples/android-architecture-components/blob/master/GithubBrowserSample/app/src/main/java/com/android/example/github/di/ViewModelModule.kt

    【讨论】:

    • 我已经浏览了提供的代码和来自 Google 的示例。我只设法在 MyCatchFragment 中获取 MyCatchViewModel。当我尝试获取 FishingSpotViewModel 时,它会引发异常 java.lang.RuntimeException: Cannot create an instance of class com.applab.fishmemommvm.viewmodel.FishingSpotViewModel
    • 我要链接上面的ViewModelModule类
    • 所以 MyCatchViewModel 有效吗?您是否为 FishingSpotViewModel 设置了所有依赖项?您的 ViewModel 构造函数上是否还有 Inject 设置,例如github.com/googlesamples/android-architecture-components/blob/…
    • 是的,这是什么问题。我错过了我的一个 ViewModel 上的注入设置。非常感谢您的帮助和指导! :)
    猜你喜欢
    • 1970-01-01
    • 2018-12-16
    • 2014-05-08
    • 2017-03-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-07-19
    相关资源
    最近更新 更多