【问题标题】:How to inject Presenter in a Fragment using Dagger2如何使用 Dagger2 在 Fragment 中注入 Presenter
【发布时间】:2017-09-26 10:44:41
【问题描述】:

如何使用 Dagger2 在 Fragment 中注入 Presenter

我已经写了下面的代码

@Module
public abstract class ActivityBuilder {

    @ContributesAndroidInjector(modules = { DetailCastActivityModule.class, FragmentDependencyProvider.class })
    abstract DetailCastActivity bindDetailCastActivity();
}

@Module
public abstract class FragmentDependencyProvider {

    @ContributesAndroidInjector(modules = CastInfoFragmentModule.class)
    abstract CastInfoFragment provideCastInfoFragmentFactory();
}

@Module
public class CastInfoFragmentModule {

    @Provides
    CastInfoMvpPresenter<CastInfoMvpView> provideCastInfoMvpPresenter(CastInfoPresenter<CastInfoMvpView> presenter) {
        return presenter;
    }

}

但即使我已经编写了提供方法,我仍然会遇到错误

Error:(24, :sunglasses: error: [dagger.android.AndroidInjector.inject(T)] com.app.nmot.ui.castdetail.info.CastInfoPresenter cannot be provided without an @Provides- or @Produces-annotated method.
com.app.nmot.ui.castdetail.info.CastInfoPresenter is injected at
com.app.nmot.ui.castdetail.info.CastInfoFragment.presenter
com.app.nmot.ui.castdetail.info.CastInfoFragment is injected at
dagger.android.AndroidInjector.inject(arg0)

评论中提到的答案并没有解决我的问题。 我已经检查了所有的注释,我正在使用 Dagger2 提供的新的 android 注入器

【问题讨论】:

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


【解决方案1】:

1- 创建你的范围

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

import javax.inject.Scope;

@Scope
@Retention(RetentionPolicy.RUNTIME)
public @interface BaseScope {
}

2- 创建你的合同

public interface FeatureContract {
   interface View {
        void onReceiveError(Throwable throwable);
        void onReceiveItems(List<Object> items);
        void showAlertDialog();
        ... //others methods
    }

    interface Presenter {
        void onInitView(Object item);
    }
}

3- 创建你的模块 (dagger2)

import dagger.Module;
import dagger.Provides;

@Module
public class FeatureContractModule {

    private final FeatureContract.View mView;

    public FeatureContractModule(FeatureContract.View view) {
        mView = view;
    }

    @Provides @BaseScope
    FeatureContract.Presenter providesFeaturePresenter(FeatureContract.View view) {
        return new FeaturePresenter(view);
    }

    @Provides @BaseScope
    FeatureContract.View providesFeatureView() {
        return mView;
    }
}

4- 创建您的演示者

public class FeaturePresenter implements FeatureContract.Presenter{

   @NonNull
   private final FeatureContract.View mView;

   public FeaturePresenter(@NonNull FeatureContract.View view){
      mView = view;
   }

   @Override
   public void onInitView(Object item){
      mView.showAlertDialog(); //<--for sample
   }
}

5- 在你的片段中

import javax.inject.Inject;

public class FeatureFragment extends Fragment implements FeatureContract.View{
@Inject FeatureContract.Presenter mPresenter;

@Override public void onActivityCreated(@Nullable Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        ((MyApplication) getActivity().getApplication()).getDataComponent()
                                                                 .plus(new FeatureContractModule(this /*view*/))
                                                                 .inject(this /*fragment*/);

        mPresenter. onInitView(null);
    }
}

5- 您的应用程序

public class MyApplication extends Application {
    //Dagger object
    private DataComponent mDataComponent;

    /**
     * Dagger Injector
     */
    public static DataComponent get(Context context) {
        MyApplication application = (MyApplication) context.getApplicationContext();
        return application.mDataComponent;
    }

    @Override
    public void onCreate() {
    super.onCreate();
    mDataComponent = DaggerDataComponent.builder()
                                        .dataModule(new DataModule(this, Locale.getDefault()))
                                        .build();
    }
    public DataComponent getDataComponent() {
        return mDataComponent;
    }   
}

6 - 创建数据组件

import javax.inject.Singleton;

import dagger.Component;

@Singleton
@Component(modules = {DataModule.class})
public interface DataComponent {
Application application();
FeatureComponent plus(FeatureContractModule module);
...
}

7 - 最后是你的 ComponentModule

import dagger.Module;
import dagger.Provides;

@BaseScope
@Subcomponent(modules = FeatureContractModule.class)
public interface FeatureComponent {
    void inject(FeatureFragment fragment);
}

我相信我没有忘记任何事情

【讨论】:

  • 查看博客:[android.jlelse.eu/… Article1) 或:[raywenderlich.com/146804/… Article2)
  • Maxim,在处理片段时是否可以不注入字段?问题是碎片网络更喜欢默认构造函数:/
  • @MaximeJallu 您的回答对我来说是正确的。感谢那。但是假设现在我想在我的演示者中注入类“A”,即在上面示例中提到的 FeaturePresenter 中。我该怎么做?目前,在 FeatureContractModule 类中,我创建了一个“Provides”注释,该注释返回新的 A()[default constructor] & 在 FeaturePresenter 类中使用“Inject”注释标记了类 A 实例。但是当我调用 A 类函数时,它是一个 NPE。
  • @MaximeJallu P.S.我不想在 FeaturePresenter 的构造函数中传递 A 类,但由于某些情况想在 Presenter 中实例化它。谢谢
【解决方案2】:

将您的CastInfoFragmentModule 抽象化并添加:

@YourScope
@Binds
abstract CastInfoMvpPresenter<CastInfoMvpView> bindPresenter(CastInfoPresenter<CastInfoMvpView> presenter);

另外,你必须在CastInfoPresenter的构造函数上添加@Inject

【讨论】:

  • 我已经在 CastInfoPresenter 的构造函数中有@Inject。你能告诉我这里自定义范围的需要是什么吗?
  • 所以你在组件的生命周期中总是得到相同的对象
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-06-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多