匕首-MissingBinding Map <Class <?如果没有@Provides注释的方法,则无法提供扩展ViewModel>,Provider <ViewModel >>

时间:2019-09-16 10:13:47

标签: java android viewmodel dagger-2 android-viewmodel

我刚开始使用Dagger Framework进行依赖注入,因此可能缺少一些琐碎的东西,但是我花了2天多的时间来研究代码和教程。

因此,我试图在我的ViewModel中使用匕首依赖注入,我发现我可以使用已实现的称为多重绑定的功能来实现这一点。我有一个AppComponent和一个ActivitySubComponentAppComponent安装了一个ViewModelFactoryModule和一个@Binds的{​​{1}},我希望此ViewModelProvider.Factory在应用程序中,因为我认为它应该独立于{{1} } 生命周期。在我的Module中有一个ActivityActivitySubComponent一个ViewModelsModule

现在,根据我的理解,我在@Binds中加入了ViewModel,这会将子组件添加到ActivitySubComponent中。

编辑:

现在,当我制作/构建项目时,出现以下错误。抱歉,最初的错误是:

ViewModelFactoryModule

AppComponent error: [Dagger/MissingBinding] java.util.Map<java.lang.Class<? extends androidx.lifecycle.ViewModel>,javax.inject.Provider<androidx.lifecycle.ViewModel>> cannot be provided without an @Provides-annotated method. java.util.Map<java.lang.Class<? extends androidx.lifecycle.ViewModel>,javax.inject.Provider<androidx.lifecycle.ViewModel>> is injected at com.mobile.presentation.viewmodels.build.ViewModelFactory(creators) com.mobile.presentation.viewmodels.build.ViewModelFactory is provided at com.mobile.app.AppComponent.obtainViewModelsFactory() 中添加以下方法后,产生了以下错误。

AppComponent.java

足够的jibber jabber,下面是相关代码:

AppComponent.java

Map<Class<? extends ViewModel>, Provider<ViewModel>> obtainMap();

ViewModelFactoryModule.java

error: [Dagger/MissingBinding] java.util.Map<java.lang.Class<? extends androidx.lifecycle.ViewModel>,javax.inject.Provider<androidx.lifecycle.ViewModel>> cannot be provided without an @Provides-annotated method.
java.util.Map<java.lang.Class<? extends androidx.lifecycle.ViewModel>,javax.inject.Provider<androidx.lifecycle.ViewModel>> is provided at
com.mobile.app.AppComponent.obtainMap()
It is also requested at:
com.mobile.presentation.viewmodels.build.ViewModelFactory(creators)
The following other entry points also depend on it:
com.mobile.app.AppComponent.obtainViewModelsFactory()

ViewModelsFactory.java

@AppScope
@Component(
        modules = {
                AppModule.class,
                ViewModelFactoryModule.class
        })
public interface AppComponent {
    App obtainApp();

    ViewModelFactory obtainViewModelsFactory();

    // I tried with adding the following line, out of sheer annoyance.
    // Map<Class<? extends ViewModel>, Provider<ViewModel>> obtainMap();
}

ActivitySubComponent.java

@Module(subcomponents = ActivitySubComponent.class)
public abstract class ViewModelFactoryModule {
    @AppScope
    @Binds
    public abstract ViewModelProvider.Factory bindViewModelFactory(ViewModelFactory viewModelFactory);
}

ViewModelsModule.java

@AppScope
public class ViewModelFactory implements ViewModelProvider.Factory {

    private final Map<Class<? extends ViewModel>, Provider<ViewModel>> creators;

    @Inject
    public ViewModelFactory(Map<Class<? extends ViewModel>, Provider<ViewModel>> creators) {
        this.creators = creators;
    }

    @SuppressWarnings("unchecked")
    @NonNull
    @Override
    public <T extends ViewModel> T create(@NonNull 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);
        }
    }
}

现在,据此我了解到// I have a separate module for my `LiveData`. @ActivityScope @Subcomponent( modules = { ActivityModule.class, ViewModelsModule.class, SplashLiveDataModule.class } ) public interface ActivitySubComponent { Activity obtainActivity(); LiveData<InitialAPIResponse> obtainLiveInitialApiResponse(); LiveData<InitialSplashApiStatus> obtainLiveInitialSplashApiStatus(); @Subcomponent.Builder interface Builder { ActivitySubComponent build(); Builder setActivityModule(ActivityModule activityModule); } } 无法直接访问@Module public abstract class ViewModelsModule { @ActivityScope @Binds @IntoMap @ViewModelKey(SplashViewModel.class) public abstract ViewModel provideVideoListViewModel(SplashViewModel viewModel); } ,但是它应该能够访问AppComponent,因为生成的ActivitySubComponent是组件的内部类(也许我缺少了一些东西),我不认为SubComponent应该绑定到应用程序的组件(我之所以这样说是因为如果我将@Subcomponent移到ViewModel我也可以运行代码,并且一切正常。),我的逻辑方法是否错误?

匕首依赖项:

ViewModelsModule

1 个答案:

答案 0 :(得分:1)

你是对的。在ActivitySubComponent中添加ViewModelFactoryModule会将子组件添加到AppComponent。

要向父级添加子组件时,有两种方法。 首先,在模块中添加子组件,然后将该模块添加到父级。其次,通过在父组件中声明一个抽象方法来返回子组件。

您已经正确使用了第一部分,但是在AppComponent中,您已经创建了一个返回ViewModelFactory的方法,该方法已经由ViewModelFactoryModule提供。这与对象图冲突,并且由于您的构建失败。您需要同时删除两个返回ViewModelFactory和Map的方法,这将解决此问题。