android - Android 上的 Dagger 2 : inject same dependency in Activity and retained Fragment

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

我有类 F1F2 的对象,我想将它们注入(inject)到保留的 Fragment 中。我还有一个依赖于 Activity 的 A 类对象,我希望将它注入(inject)到该 Activity 和附加到该 Activity 的 Fragment Manager 的保留 Fragment 中。我写了下面的代码。首先,Activity 依赖的模块:

@Module
public class MainActivityModule {
    private Activity mActivity;

    public MainActivityModule(Activity activity) {
        mActivity = activity;
    }

    @Provides
    @ActivityScope
    public A provideA() {
        return new A(mActivity);
    }
}

然后,相应的组件必须使 A 对象可用于其依赖组件:

@ActivityScope
@Component(modules = {MainActivityModule.class})
public interface MainActivityComponent {
    void inject(MainActivity activity);

    // make the A object available to dependent components
    A getA();
}

我也写了Fragment相关的模块:

@Module
public class FragmentModule {
    @Provides
    @FragmentScope
    public F1 provideF1() {
        return new F1();
    }

    @Provides
    @FragmentScope
    public F2 provideF2() {
        return new F2();
    }
}

及其对应的组件:

@FragmentScope
@Component(modules = {FragmentModule.class}, dependencies = {MainActivityComponent.class})
public interface FragmentComponent {
    void inject(MyFragment presenter);
}

最后,我在 Activity 中注入(inject)了对 A 的依赖,我还需要在 Activity 上调用特定的生命周期方法。 Activity 还提供了获取组件的方法,以便 Fragment 在构建自己的组件时能够使用它:

// in MainActivity.onCreate
mActivityComponent = DaggerMainActivityComponent.builder()
        .mainActivityModule(new MainActivityModule(this))
        .build();
mActivityComponent.inject(this);
mA.onCreate();

我也尝试在 fragment 中注入(inject)对 AF1F2 的依赖:

// in MyFragment.onCreate
FragmentComponent component = DaggerFragmentComponent.builder()
        .fragmentModule(new FragmentModule())
        .mainActivityComponent(((MainActivity) getActivity()).getComponent())
        .build();
component.inject(this);

但是,由于 Fragment 被保留,当 Activity 被系统响应配置更改(例如设备旋转)销毁和重新创建时,Fragment 维护对旧 A 实例的引用,而新的 Activity 已经正确地重新创建了一个新的 A 实例。要解决此问题,我必须创建 FragmentComponent 并在 MyFragment.onActivityCreated 而不是 MyFragment.onCreate 中注入(inject)依赖项。另一方面,这意味着每次销毁和重新创建 Activity 时,都会重新创建 F1F2 依赖项;但它们是 Fragment 范围内的依赖项,因此它们应该遵循 Fragment 的生命周期而不是 Activity 的生命周期。

因此,我的问题如下:是否可以在保留的 Fragment 中注入(inject)不同范围的依赖项?理想情况下,F1F2依赖应该注入(inject)MyFragment.onCreate,而A依赖应该注入(inject)MyFragment.onActivityCreated。我尝试使用两个不同的组件,但似乎无法执行部分注入(inject)。目前,我最终在 MyFragment.onActivityCreated 中添加了 Fragment A 依赖项的显式重新分配,但这并不是真正的注入(inject),你知道的。可以用更好的方式完成吗?

最佳答案

考虑到你保留的 fragment 比你的 Activity 长,我敢打赌,正确的方法是让 FragmentScope 包含 ActivityScope,而不是反之亦然。

意思是你的 FragmentComponent 会有

@FragmentScope
@Component(modules = {FragmentModule.class})
public interface FragmentComponent {
    void inject(MyFragment presenter);
}

你的 Activity 组件会有

@ActivityScope
@Component(dependencies = {FragmentComponent.class}, modules = {MainActivityModule.class})
public interface MainActivityComponent extends FragmentComponent { //provision methods
    void inject(MainActivity activity);

    // make the A object available to dependent components
    A getA();
}

如果您的 Fragment 注入(inject)类不依赖 Activity 模块作为依赖项,则这是可能的。

这可以用类似的东西来完成

public class MainActivity extends AppCompatActivity {

    private MainActivityComponent mainActivityComponent;

    private MyFragment myFragment;

    @Override
    public void onCreate(Bundle saveInstanceState) {
         super.onCreate(saveInstanceState);
         setContentView(R.layout.activity_main);

         if(saveInstanceState == null) { // first run
             myFragment = new MyFragment(); //headless retained fragment
             getSupportFragmentManager()
                .beginTransaction()
                .add(myFragment, MyFragment.class.getName()) //TAG
                .commit();
         } else {
             myFragment = (MyFragment)(getSupportFragmentManager()
                               .findFragmentByTag(MyFragment.class.getName()));
         }
    }

    @Override
    public void onPostCreate() {
         mainActivityComponent = DaggerMainActivityComponent.builder()
              .fragmentComponent(myFragment.getComponent())
              .build();
    }
}

public class MyFragment extends Fragment {
    public MyFragment() {
         this.setRetainInstance(true);
    }

    private FragmentComponent fragmentComponent;

    @Override
    public void onCreate(Bundle saveInstanceState) {
        super.onCreate(saveInstanceState);
        this.fragmentComponent = DaggerFragmentComponent.create();
    }

    public FragmentComponent getFragmentComponent() {
        return fragmentComponent;
    }
}

编辑:

public class MyFragment extends Fragment {
    public MyFragment() {
         this.setRetainInstance(true);
         this.fragmentComponent = DaggerFragmentComponent.create();
    }

    private FragmentComponent fragmentComponent;

    public FragmentComponent getFragmentComponent() {
        return fragmentComponent;
    }
}

public class MainActivity extends AppCompatActivity {

    private MainActivityComponent mainActivityComponent;

    private MyFragment myFragment;

    @Inject
    A mA;

    @Override
    public void onCreate(Bundle saveInstanceState) {
         super.onCreate(saveInstanceState);
         setContentView(R.layout.activity_main);

         if(saveInstanceState == null) { // first run
             myFragment = new MyFragment(); //headless retained fragment
             getSupportFragmentManager()
                .beginTransaction()
                .add(myFragment, MyFragment.class.getName()) //TAG
                .commit();
         } else {
             myFragment = (MyFragment)(getSupportFragmentManager().findFragmentByTag(MyFragment.class.getName()));
         }
         mainActivityComponent = DaggerMainActivityComponent.builder()
              .fragmentComponent(myFragment.getComponent())
              .build();
         mainActivityComponent.inject(this);
         mA.onCreate();
    }
}

关于android - Android 上的 Dagger 2 : inject same dependency in Activity and retained Fragment,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32113953/

相关文章:

android - Xamarin garba 集合经常运行

java - 方向更改后按钮和菜单停止工作

android - 为什么大多数linux可执行文件在android系统中都是ET_DYN类型

android - "Android java.lang.NoClassDefFoundError: org.jsoup.Jsoup"将jar添加到/libs不起作用?

java - Android 片段被另一个片段覆盖

android - 将 @ActivityScoped 对象注入(inject)到 Fragment 中

java - Dagger 2 不生成子组件实现

c# - 使用 Factory 获取注入(inject)的对象

android - "flutter pub get"无法获取依赖插件

android - 操作栏检测 fragment 中的后退按钮单击