java - 如果没有 @Inject 构造函数或 @Provides 注释的方法,则无法提供 - Dagger 2

标签 java android dagger-2 dagger

我正在使用 Dagger 2,但出现了这个奇怪的错误,到目前为止对我来说似乎没有什么不对,但显然缺少了一些东西。任何帮助将不胜感激。

Error:(16, 8) error: [dagger.android.AndroidInjector.inject(T)] com.example.user.viewmodel.TripViewModel cannot be provided without an @Inject constructor or from an @Provides-annotated method. This type supports members injection but cannot be implicitly provided.
com.example.user.viewmodel.TripViewModel is injected at
com.example.user.di.ViewModelModule.bindTripViewModel(tripViewModel)
java.util.Map<java.lang.Class<? extends android.arch.lifecycle.ViewModel>,javax.inject.Provider<android.arch.lifecycle.ViewModel>> is injected at
com.example.user.di.TripViewModelFactory.<init>(creators)
com.example.user.di.TripViewModelFactory is injected at
com.example.user.di.ViewModelModule.bindViewModelFactory(factory)
android.arch.lifecycle.ViewModelProvider.Factory is injected at
com.example.user.fragment.HomeFragment.viewModelFactory
com.example.user.fragment.HomeFragment is injected at
dagger.android.AndroidInjector.inject(arg0)

代码如下:

AppModule.java

@Module(includes = ViewModelModule.class)
class AppModule {
    @Singleton
    @Provides
    MyRoomDatabase providesRoomDatabase(Application application) {
        return Room.databaseBuilder(application,
                MyRoomDatabase.class, "name_db").build();
    }

    @Singleton
    @Provides
    TripRepository provideTripRepository(TripDao tripDao){
        return new TripRepository(tripDao);
    }

    @Singleton
    @Provides
    TripDao provideTripDao(MyRoomDatabase myRoomDatabase){
        return myRoomDatabase.getTripDao();
    }

}

ViewModelModule.java

@Module
public abstract class ViewModelModule {
    @Binds
    @IntoMap
    @ViewModelKey(TripViewModel.class)
    abstract ViewModel bindTripViewModel(TripViewModel tripViewModel);

    @Binds
    abstract ViewModelProvider.Factory bindViewModelFactory(TripViewModelFactory factory);
}

MainActivityModule.java

@Module
public abstract class MainActivityModule {
    @ContributesAndroidInjector(modules = FragmentBuildersModule.class)
    abstract MainActivity contributeMainActivity();
}

FragmentBuildersModule.java

@Module
public abstract class FragmentBuildersModule {
    @ContributesAndroidInjector
    abstract HomeFragment contributeRepoFragment();
}

AppComponent.java

@Singleton
@Component(modules = {
        AndroidInjectionModule.class,
        AppModule.class,
        MainActivityModule.class
})
public interface AppComponent {
    @Component.Builder
    interface Builder {
        @BindsInstance
        Builder application(Application application);

        AppComponent build();
    }
    void inject(FuelApp fuelApp);
}

AppInjector.java

public class AppInjector {
    private AppInjector() {}
    public static void init(FuelApp fuelApp) {
        DaggerAppComponent.builder().application(fuelApp)
                .build().inject(fuelApp);
        fuelApp.registerActivityLifecycleCallbacks(new Application.ActivityLifecycleCallbacks() {
                    @Override
                    public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
                        handleActivity(activity);
                    }

                    @Override
                    public void onActivityStarted(Activity activity) {

                    }

                    @Override
                    public void onActivityResumed(Activity activity) {

                    }

                    @Override
                    public void onActivityPaused(Activity activity) {

                    }

                    @Override
                    public void onActivityStopped(Activity activity) {

                    }

                    @Override
                    public void onActivitySaveInstanceState(Activity activity, Bundle outState) {

                    }

                    @Override
                    public void onActivityDestroyed(Activity activity) {

                    }
                });
    }

    private static void handleActivity(Activity activity) {
        if (activity instanceof HasSupportFragmentInjector) {
            AndroidInjection.inject(activity);
        }
        if (activity instanceof FragmentActivity) {
            ((FragmentActivity) activity).getSupportFragmentManager()
                    .registerFragmentLifecycleCallbacks(
                            new FragmentManager.FragmentLifecycleCallbacks() {
                                @Override
                                public void onFragmentCreated(FragmentManager fm, Fragment f,
                                                              Bundle savedInstanceState) {
                                    if (f instanceof Injectable) {
                                        AndroidSupportInjection.inject(f);
                                    }
                                }
                            }, true);
        }
    }
}

ViewModelKey.java

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

TripViewModelFactory.java

@Singleton
public class TripViewModelFactory implements ViewModelProvider.Factory {
    private final Map<Class<? extends ViewModel>, Provider<ViewModel>> creators;

    @Inject
    public TripViewModelFactory(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);
        }
    }
}

我已经寻找了很多解决方案,但尚未找到可行的解决方案。请随时分享任何评论。谢谢。

编辑:以下是我在 fragment 类中注入(inject) TripViewModel 的方法:

@Inject
ViewModelProvider.Factory viewModelFactory;
.
.
viewModel = ViewModelProviders.of(this, viewModelFactory).get(TripViewModel.class);

最佳答案

我已经解决了这个问题。该错误是由于错误的 ViewModel 构造函数声明引起的。在我的代码中,我使用工厂类 (TripViewModelFactory),以便将 TripViewModel 类与具有由 Dagger 注入(inject)的非零参数的构造函数一起使用。我的 TripViewModel 类构造函数声明有问题,并且未调用我打算由工厂类调用的构造函数。因此,未创建 ViewModel 实例,这又导致了我的问题中给出的错误。

此外,如果您使用我在问题中共享的相同代码结构,则从工厂类创建 viewmodel 实例的 fragment 类必须实现 Injectable 接口(interface)。这个错误在我的代码中造成了另一个错误,很高兴与大家分享。

关于java - 如果没有 @Inject 构造函数或 @Provides 注释的方法,则无法提供 - Dagger 2,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48612377/

相关文章:

java - 如何使用 Selenium 和 Java 找到并单击选择 boolean 复选框

java - 使用 Spring 和 Caffeine 定义多个缓存配置

java - 在 Maven 中调试?

java - 带有 Java 的 Google 自然语言 API - setLanguage

javascript - Android WebView 缓存 list 应用程序不刷新 Javascript 文件

android - 如何使用 Dagger2 在 Android 中注入(inject) LifecycleOwner?

android - 如何将文本放置在底部中心

android - Android和PC之间的音频路由会产生白噪声

android - 使用 Dagger-2 和 Autofactory 时实现辅助注入(inject)的问题

android - 使用 Dagger 2 注入(inject)子类的最佳方法是什么?