注入具有活动上下文依赖关系的ViewModels

时间:2018-08-26 22:27:50

标签: android dagger-2

我使用的是dagger.android,想注入ViewModels。另一方面,我有一个ApiModule,它取决于活动上下文,

这里是AppComponent

@Singleton
@Component(modules = {
        AndroidSupportInjectionModule.class,
        AppModule.class,
        ActivityBindingModule.class,
        ViewModelModule.class
})
public interface AppComponent extends AndroidInjector<MyApp> {
    @Component.Builder
    abstract class Builder extends AndroidInjector.Builder<MyApp> {}
}

ViewModelModule提供了ViewModelProvider.Factory

@Module
abstract class ViewModelModule {
    @Binds
    abstract ViewModelProvider.Factory bindViewModelFactory(MyAppViewModelFactory factory);
}

这里是ActivityBindingModule

@Module
abstract class ActivityBindingModule {
    //MainActivity
    @ActivityScoped
    @ContributesAndroidInjector(modules = {
            MainActivityModule.class,
            ApiModule.class
    })
    abstract MainActivity contributeMainActivityInjector();

    @Module
    abstract class MainActivityModule {
        @ActivityScoped
        @Binds
        abstract Activity bindMainActivity(MainActivity activity);

        @Binds
        @IntoMap
        @ViewModelKey(UserViewModel.class)
        abstract ViewModel bindUserViewModel(UserViewModel userViewModel);
    }

    //SecondActivity
    @ActivityScoped
    @ContributesAndroidInjector(modules = {
            SecondActivityModule.class,
            ApiModule.class
    })
    abstract SecondActivity contributeSecondActivityInjector();

    @Module
    abstract class SecondActivityModule {
        @ActivityScoped
        @Binds
        abstract Activity bindSecondActivity(SecondActivity activity);

        @Binds
        @IntoMap
        @ViewModelKey(DetailViewModel.class)
        abstract ViewModel bindDetailViewModel(DetailViewModel detailViewModel);
    }
}

我有以下注入层次结构:

  • MainActivity --inject--> ViewModelProvider.Factory --inject--> MyAppViewModelFactory --inject--> UserViewModel --inject--> UserRepository --inject--> ApiService --inject--> Activity context

  • SecondActivity --inject--> ViewModelProvider.Factory --inject--> MyAppViewModelFactory --inject--> DetailViewModel --inject--> DetailRepository --inject--> ApiService --inject--> Activity context

我们提供:

    Activity(和MainActivityModule)上的
  • SecondActivityModule上下文
  • ApiService上的ApiModule(已添加到ActivityBindingModule上每个活动的模块中)
  • UserRepositoryDetailRepository@Singleton
  • {{1}上的UserViewModelMainActivityModule上的DetailViewModel
  • SecondActivityModule是@Singleton

这里是MyAppViewModelFactory

MyAppViewModelFactory

我收到此错误:

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

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

    @SuppressWarnings("unchecked")
    @Override
    @NonNull
    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);
        }
    }
}

我尝试将error: [Dagger/MissingBinding] [dagger.android.AndroidInjector.inject(T)] java.util.Map<java.lang.Class<? extends android.arch.lifecycle.ViewModel>,javax.inject.Provider<android.arch.lifecycle.ViewModel>> cannot be provided without an @Provides-annotated method. java.util.Map<java.lang.Class<? extends android.arch.lifecycle.ViewModel>,javax.inject.Provider<android.arch.lifecycle.ViewModel>> is injected at com.example.viewmodels.MyAppViewModelFactory.<init>(creators) com.example.viewmodels.MyAppViewModelFactory is injected at com.example.di.ViewModelModule.bindViewModelFactory(factory) android.arch.lifecycle.ViewModelProvider.Factory is injected at com.example.activities.MainActivity.viewModelFactory com.example.activities.MainActivity is injected at dagger.android.AndroidInjector.inject(T) component path: com.example.di.AppComponent ? com.example.di.ActivityBindingModule_ContributeMainActivityInjector.MainActivitySubcomponent (从bindUserViewModel)和MainActivityModule(从bindDetailViewModel)移到SecondActivityModule,但出现此错误:

ViewModelModule

我在这里想念什么? iosched项目可以毫无问题地完成同样的事情

2 个答案:

答案 0 :(得分:0)

首先,您需要在“应用程序”和“活动”级别重构Dagger2设置。 其次,您的ViewModelProviderFactory类有点复杂。现在,我将为您重组代码。

应用程序级别

AppComponent

@Singleton
@Component(modules = {
    AndroidSupportInjectionModule.class,
    AppModule.class,
    ActivityBindingModule.class
})
public interface AppComponent extends AndroidInjector<MyApp> {
@Component.Builder
abstract class Builder extends AndroidInjector.Builder<MyApp> {}
}

ActivityBindingModule

@Module
abstract class ActivityBindingModule {

  @ContributesAndroidInjector(modules = MainActivityModule.class)
  abstract MainActivity contributeMainActivity();

  //This goes for other activities
}

AppModule此类仅提供常见的类,并且可以在  整个应用程序中的任何活动。

@Module
class AppModule {

  @Singleton
  @Provides
  //Your ApiService interface comes here
  //Retrofit
  //Database
}

App类应简化DaggerApplication。这会自动注入其成员

  class MyApp extends DaggerApplication

      @Override
      public void onCreate() {
        super.onCreate();
      }

      @Override
      protected AndroidInjector<? extends DaggerApplication> 
      applicationInjector() {
        return DaggerHorizonMainComponent.builder().create(this);
   }

活动级别

MainActivityModule这是您拥有ViewModelViewModelProviderFactory

的地方
@Module
class MainACtivityModule {

@Provides
MainActivityViewModel provideMainActivityViewModel(){
    return new MainActivityViewModel();
}

@Provides
ViewModelProvider.Factory provideViewModelProvider(MainActivityViewModel 
viewModel){
    return new ViewModelProviderFactory<>(viewModel);
}

//Your repository comes here too
}

ViewModel

 class MyViewModel extends ViewModel {

 @Inject
 public MyViewModel(){
 }
 }

ViewModelProviderFactory只需复制此代码

 public class ViewModelProviderFactory<V> implements 
      ViewModelProvider.Factory {
        private V viewModel;

        public ViewModelProviderFactory(V viewModel) {
           this.viewModel = viewModel;
        }

        @Override
        public <T extends ViewModel> T create(Class<T> modelClass) {
            if (modelClass.isAssignableFrom(viewModel.getClass())) {
                 return (T) viewModel;
            }
            throw new IllegalArgumentException("Unknown class name");
        }
    }

最后,在您的MainActivity类中,注入ViewModelProviderFactory。您无需在此处注入Dagger,因为您可以将其扩展到DaggerAppCompatActivity

   public class Mainactivity extends DaggerAppCompatActivity{

       @Inject
       ViewModelProvider.Factory factory;
       private MyViewModel viewModel;

       @Override
       protected void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
       //You set your view here
       viewmodel = 
       ViewModelProviders.of(this,factory).get(MyViewModel.class);

       }
     }

答案 1 :(得分:0)

所有设置听起来正确。 主要原因是未提供ApiService

  

错误:[Dagger / MissingBinding]   [dagger.android.AndroidInjector.inject(T)]   如果没有以下提示,则无法提供tk.medlynk.medlynk.http.ApiService:   @提供注释的方法。

要解决此问题,您只需在某个模块中提供它即可。

class AppModule {
    @Singleton
    @Provides
    fun provideApiService(): ApiService {
        ....
    }
}