Android上的Dagger 2:在Activity中注入相同的依赖项并保留Fragment

Giu*_*lli 15 android dependency-injection android-fragments dagger dagger-2

我有一个类的对象F1F2我想在保留片段注入.我还有一个A依赖于Activity 的类对象,我希望它被注入到该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);
    }
}
Run Code Online (Sandbox Code Playgroud)

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

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

    // make the A object available to dependent components
    A getA();
}
Run Code Online (Sandbox Code Playgroud)

我还写了与Fragment相关的模块:

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

    @Provides
    @FragmentScope
    public F2 provideF2() {
        return new F2();
    }
}
Run Code Online (Sandbox Code Playgroud)

及其相应的组成部分:

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

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

// in MainActivity.onCreate
mActivityComponent = DaggerMainActivityComponent.builder()
        .mainActivityModule(new MainActivityModule(this))
        .build();
mActivityComponent.inject(this);
mA.onCreate();
Run Code Online (Sandbox Code Playgroud)

我尝试注入的依赖关系A,F1,F2在片段,太:

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

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

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

Epi*_*rce 8

考虑到你保留的碎片寿命比你的活动长,我敢打赌,正确的方法是使FragmentScope包含ActivityScope,而不是反过来.

意味着你的FragmentComponent会有

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

你的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();
}
Run Code Online (Sandbox Code Playgroud)

如果Fragment注入的类不依赖于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();
    }
}
Run Code Online (Sandbox Code Playgroud)

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

编辑:

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();
    }
}
Run Code Online (Sandbox Code Playgroud)