【问题标题】:Can't inject RecyclerView ViewHolder in android with dagger 2 and MVVM无法使用 dagger 2 和 MVVM 在 android 中注入 RecyclerView ViewHolder
【发布时间】:2016-08-02 15:03:05
【问题描述】:

您好,我正在使用 MVVM 和 dagger 2 重构我的应用程序,我正在关注这个示例 [Countries App][1][1]:https://github.com/patloew/countries/tree/master/app

我已成功注入 LoginActivity、RestAPi 等,但在我的下一个活动中,我有一个回收器视图,视图持有者在编译时出错。 这是我的代码:

组件

@PerApplication
@Component(modules = {AppModule.class, NetworkApiModule.class, ViewModelModule.class})
public interface DiComponent {
  @AppContext
  Context context();
  Resources resources();
  APIService apiService();
}
@PerActivity
@Component(dependencies = {DiComponent.class},modules ={ActivityModules.class, ViewModelModule.class})
public interface DiActivitiesComponent {
   void inject(LoginActivity activity);
   void inject(MainActivity activity);
}
@PerViewHolder
@Component(dependencies = DiComponent.class, modules ={ViewHolderModule.class, ViewModelModule.class})
public interface DiViewHolderComponent {
   void inject(MenuViewHolder viewHolder);
}

模块

@Module
public class AppModule {
  private final Application mApp;
  public AppModule(Application app) {
     mApp = app;
  }
  @Provides
  @PerApplication
  @AppContext
  Context provideAppContext() {
      return mApp;
   }
  @Provides
  @PerApplication
  Resources provideResources(){return mApp.getResources();}
}
@Module
public class ActivityModules {
  private final BaseActivity baseActivity;
  public ActivityModules(BaseActivity baseActivity) {
     this.baseActivity = baseActivity;
  }
  @Provides
  @PerActivity
  @ActivityContext
  Context provideActivityContext() { return baseActivity; }

  @Provides
  @PerActivity
  ProgressDialog provideProgressDialog() {
    ProgressDialog progress;
    progress = new ProgressDialog(baseActivity);
    progress.setMessage("Loading...");
    progress.setCancelable(false);
    return progress;
  }
  @Provides
  @PerActivity
  Validator validator(){
    return new Validator(baseActivity);
  }
  @Provides
  @PerActivity
  Navigator provideNavigator() { return new ActivityNavigator(baseActivity); }
}
@Module
public class ViewHolderModule {

  private final AppCompatActivity activity;
  public ViewHolderModule(View itemView) {
    activity = (AppCompatActivity) itemView.getContext();
  }
  @Provides
  @PerViewHolder
  @ActivityContext
  Context provideActivityContext() { return activity; }

  @Provides
  @PerViewHolder
  FragmentManager provideFragmentManager() { return activity.getSupportFragmentManager(); }

  @Provides
  @PerViewHolder
  Navigator provideNavigator() { return new ActivityNavigator(activity); }
}
@Module
public abstract class ViewModelModule {
  @Binds
  abstract Observable bindLoginViewModel(LoginViewModel loginViewModel);
  @Binds
  abstract Observable bindMainViewModel(MainViewModel mainViewModel);

  @Binds
  abstract MenuModelView bindCMenuViewModel(MenuModelView menuModelView);
}

应用

public class MyApplication extends Application {
  private static MyApplication instance=null;
  private static DiComponent component=null;
  @Override
  public void onCreate() {
    super.onCreate();
    instance=this;
    component = DaggerDiComponent.builder()
            .appModule(new AppModule(this))
            .build();
  }
  public static MyApplication getInstance(){
    return instance;
  }
  public static DiComponent getComponent() {
    return component;
  }
  public static Resources getRes() { return instance.getResources(); }
}

基础活动

public abstract class BaseActivity<B extends ViewDataBinding,V extends MvvmViewModel> extends AppCompatActivity{
  public static final String TAG = "BaseActivity";
  protected B binding;
  @Inject protected V viewModel;
  @Inject protected Validator validator;
  @Inject protected ProgressDialog progress;
  private DiActivitiesComponent component;

  protected final void setAndBindContentView(@LayoutRes int layoutResId, @Nullable Bundle savedInstanceState) {
    if(viewModel == null) { throw new IllegalStateException("viewModel must not be null and should be injected via activityComponent().inject(this)"); }
    binding = DataBindingUtil.setContentView(this, layoutResId);
    binding.setVariable(BR.vm, viewModel);
    viewModel.attachView((MvvmView) this, savedInstanceState);
  }
  protected final DiActivitiesComponent activityComponent() {
    if(component == null) {
        component = DaggerDiActivitiesComponent.builder()
                .diComponent(MyApplication.getComponent())
                .activityModules(new ActivityModules(this))
                .build();
    }
    return component;
  }
  @Override
  @CallSuper
  protected void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);
    if(viewModel != null) { viewModel.saveInstanceState(outState); }
  }
  @Override
  @CallSuper
  protected void onDestroy() {
    super.onDestroy();
    if(viewModel != null) { viewModel.detachView(); }
    viewModel = null;
    binding = null;
    component = null;
  }
}

主活动

public class MainActivity extends BaseBarActivity<ActivityMainBinding, MainViewModel> implements MvvmView {
  @Inject MenuListAdapter adapter;
  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    activityComponent().inject(this);
    setAndBindContentView(R.layout.activity_main, savedInstanceState);
    loadToolbar(R.string.empty_title);
    ButterKnife.bind(this);

    ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
    drawer.setDrawerListener(toggle);
    toggle.syncState();

    binding.lstMenuItems.setHasFixedSize(true);
    binding.lstMenuItems.setLayoutManager(new LinearLayoutManager(this));
    binding.lstMenuItems.setAdapter(adapter);

    adapter.setMenuItems(menuItems);
    adapter.notifyDataSetChanged();
  }
}

视图模型 基础视图模型

public abstract class BaseViewModel<V extends MvvmView> extends BaseObservable implements MvvmViewModel<V> {
  @Inject protected Provider<Navigator> navigator;
  private V mView;
  public V getView() {
    return mView;
  }
  @Override
  @CallSuper
  public void attachView(@NonNull V view, @Nullable Bundle savedInstanceState) {
    mView = view;
    if(savedInstanceState != null) { restoreInstanceState(savedInstanceState); }
  }
  @Override
  @CallSuper
  public void detachView() {
    mView = null;
  }
  @Override
  public void saveInstanceState(@NonNull Bundle outState) { }
  @Override
  public void restoreInstanceState(@NonNull Bundle savedInstanceState) { }
}

主视图模型

@PerActivity
public class MainViewModel extends BaseViewModel<MvvmView> {
  private Context context;
  @Inject
  public MainViewModel(@AppContext Context context) {
    this.context=context;
  }    
 }

项目视图模型

@PerViewHolder
public class MenuModelView extends BaseViewModel<MvvmView> {
  private PegasusMenuItem item;
  private final Context context;
  @Inject
  public MenuModelView(@AppContext Context context){
    this.context=context.getApplicationContext();
  }
  @Bindable
  public Drawable getImage() {
    return  AppCompatDrawableManager.get().getDrawable(context,item.getResId());
  }
  public String getTextData() {
    return item.getText();
  }
  public void update(PegasusMenuItem item) {
    this.item = item;
    notifyChange();
  }
}

BaseViewHolder

public abstract class BaseViewHolder<B extends ViewDataBinding, V extends MvvmViewModel> extends RecyclerView.ViewHolder {
  protected B binding;
  @Inject protected V viewModel;
  private DiViewHolderComponent viewHolderComponent;
  private View itemView = null;

  public BaseViewHolder(View itemView) {
    super(itemView);
    this.itemView = itemView;
  }
  protected final DiViewHolderComponent viewHolderComponent() {
    if(viewHolderComponent == null) {
        viewHolderComponent = DaggerDiViewHolderComponent.builder()
                .diComponent(MyApplication.getComponent())
                .viewHolderModule(new ViewHolderModule(itemView))
                .build();
        itemView = null;
    }
    return viewHolderComponent;
  }
  protected final void bindContentView(@NonNull View view) {
    if(viewModel == null) { throw new IllegalStateException("viewModel must not be null and should be injected via viewHolderComponent().inject(this)"); }
    binding = DataBindingUtil.bind(view);
    binding.setVariable(BR.vm, viewModel);
    viewModel.attachView((MvvmView) this, null);
  }
  public final V viewModel() { return viewModel; }
}

MenuViewHolder

public class MenuViewHolder  extends BaseViewHolder<MenuItemBinding, MenuModelView> implements MvvmView {
  public MenuViewHolder(View v) {
    super(v);
    viewHolderComponent().inject(this);
    bindContentView(v);
  }
}

布局 activity_main

<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
  <data>
    <variable name="vm" type="com.package.name.ViewModels.MainViewModel" />
  </data>
  <android.support.v4.widget.DrawerLayout
    android:id="@+id/drawer_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true"
    tools:openDrawer="start">
      <include
        layout="@layout/app_bar_main"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
      <android.support.design.widget.NavigationView
        android:id="@+id/nav_view"
        android:layout_marginTop="@dimen/activity_vertical_margin"
        android:layout_width="@dimen/menu_item_size"
        android:layout_height="match_parent"
        android:layout_gravity="start"
        android:fitsSystemWindows="true">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:background="@color/gray_color"
            android:orientation="vertical">

            <android.support.v7.widget.RecyclerView
                android:id="@+id/lst_menu_items"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:layout_weight="1"
                android:dividerHeight="0dp"
                android:divider="@null" />
        </LinearLayout>
    </android.support.design.widget.NavigationView>
  </android.support.v4.widget.DrawerLayout>
</layout>

菜单项

<layout xmlns:android="http://schemas.android.com/apk/res/android">
  <data>
    <variable name="vm" type="com.package.name.ViewModels.ViewHolders.MenuModelView" />
  </data>
  <RelativeLayout
    android:layout_width="@dimen/menu_item_size"
    android:layout_height="@dimen/menu_item_size"
    android:paddingTop="@dimen/margin_fields"
    android:paddingBottom="@dimen/margin_fields"
    android:background="@color/gray_color">
      <ImageView
        android:layout_width="@dimen/menu_item_icon_size"
        android:layout_height="@dimen/menu_item_icon_size"
        android:id="@+id/img_menu_icon"
        android:src="@{vm.image}"
        android:scaleType="centerInside"
        android:layout_centerHorizontal="true" />
      <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="@{vm.textData}"
        android:id="@+id/txt_menu_title"
        android:textSize="@dimen/text_xsmall_size"
        android:gravity="center"
        android:layout_below="@+id/img_menu_icon"
        android:textColor="@color/white_color" />
  </RelativeLayout>
</layout>

如果我在 DiViewHolderComponent 中注释注入方法,并且在视图持有者中代码编译并启动应用程序,我已经检查了很多次代码但我不知道问题出在哪里,请帮助!!!

错误日志

/Users/.../Views/Activities/BaseActivity.java
Error:(20, 42) error: cannot find symbol class BR
Error:(21, 63) error: cannot find symbol class DaggerDiActivitiesComponent
/Users/.../Views/Activities/LoginActivity.java
Error:(16, 54) error: package com.mifinity.app2soft.mifinitymvvm.databinding does not exist
Error:(25, 49) error: cannot find symbol class LoginActivityBinding
/Users/.../Views/Activities/MainActivity.java
Error:(23, 54) error: package com.package.name.databinding does not exist
Error:(30, 51) error: cannot find symbol class ActivityMainBinding
/Users/.../Views/ViewHolders/BaseViewHolder.java
Error:(9, 42) error: cannot find symbol class BR
Error:(10, 63) error: cannot find symbol class DaggerDiViewHolderComponent
/Users/.../Views/ViewHolders/MenuViewHolder.java
Error:(7, 54) error: package com.package.name.databinding does not exist
Error:(12, 53) error: cannot find symbol class MenuItemBinding
/Users/.../Views/ViewHolders/LastTransactionsViewHolder.java
Error:(7, 54) error: package com.mifinity.app2soft.mifinitymvvm.databinding does not exist
Error:(12, 64) error: cannot find symbol class AccountItemBinding
/Users/.../Views/ViewHolders/AmountViewHolder.java
Error:(7, 54) error: package com.package.name.databinding does not exist
Error:(13, 54) error: cannot find symbol class BalanceItemBinding

/Users/.../Views/Fragments/BaseFragment.java
Error:(18, 42) error: cannot find symbol class BR
Error:(19, 63) error: cannot find symbol class DaggerFragmentComponent
/Users/developer/22Technology/Android     Projects/.../Views/Fragments/OverviewFragment.java
Error:(22, 54) error: package com.package.name.databinding does not exist
Error:(33, 52) error: cannot find symbol class OverviewFragmentBinding
/Users/.../MyApplication.java
Error:(6, 63) error: cannot find symbol class DaggerDiComponent
Note: Generating a MembersInjector for com.package.name.Views.Activities.MainActivity. Prefer to run the dagger processor over that class instead.
Error:Execution failed for task ':app:compileDebugJavaWithJavac'.
> java.lang.StackOverflowError

【问题讨论】:

  • 请包含实际的错误信息

标签: android mvvm dagger-2 android-viewholder android-databinding


【解决方案1】:

您似乎没有向“父”组件添加配置方法,即。双分量。 试试这个:

@PerApplication
@Component(modules = {AppModule.class, NetworkApiModule.class, ViewModelModule.class})
public interface DiComponent {
  @AppContext
  Context context();
  Resources resources();
  APIService apiService();


  Context provideAppContext();
  Resources provideResources();
  /**etc. put other @provide 
  method interfaces of modules
  which are other components dependent on here*/
}

比你使用的模块abstract class ViewModelModule ,Dagger 似乎不可能知道要注入哪个模块。它应该只用于实现的类。

在清理项目并构建之后。

添加:看官方示例项目https://github.com/google/dagger/tree/master/examples/android-activity-graphs

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-12-08
    相关资源
    最近更新 更多