保持されているFragmentに注入するクラスF1
およびF2
のオブジェクトがあります。また、Activityに依存するクラスA
のオブジェクトがあり、そのアクティビティと、そのActivityのFragment Managerに接続されている保持されているFragmentに挿入する必要があります。次のコードを書きます。まず、アクティビティ依存関係のモジュール:
@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();
}
フラグメント関連のモジュールも作成します。
@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);
}
最後に、A
への依存関係をアクティビティに挿入します。ここで、特定のライフサイクルメソッドを呼び出す必要もあります。アクティビティはまた、コンポーネントを取得するメソッドを提供し、フラグメントが独自のコンポーネントを構築するときにそれを使用できるようにします。
// in MainActivity.onCreate
mActivityComponent = DaggerMainActivityComponent.builder()
.mainActivityModule(new MainActivityModule(this))
.build();
mActivityComponent.inject(this);
mA.onCreate();
そして、フラグメント内のA
、F1
、F2
への依存関係も注入しようとします:
// in MyFragment.onCreate
FragmentComponent component = DaggerFragmentComponent.builder()
.fragmentModule(new FragmentModule())
.mainActivityComponent(((MainActivity) getActivity()).getComponent())
.build();
component.inject(this);
ただし、フラグメントが保持されるため、構成の変更(デバイスのローテーションなど)に反応してシステムによってアクティビティが破棄および再作成されると、フラグメントは古いA
インスタンスへの参照を維持しますが、新しいアクティビティはそれに伴う新しいA
インスタンスを正しく再作成しました。この問題を回避するには、FragmentComponent
を作成し、MyFragment.onActivityCreated
ではなくMyFragment.onCreate
に依存関係を挿入する必要があります。一方、これは、アクティビティが破棄されて再作成されるたびに、F1
およびF2
依存関係が再作成されることを意味します。ただし、これらはフラグメントスコープの依存関係であるため、アクティビティではなくフラグメントライフサイクルに従う必要があります。
したがって、私の質問は次のとおりです。保持されたフラグメントに異なるスコープの依存関係を挿入することは可能ですか?理想的には、F1
およびF2
の依存関係をMyFragment.onCreate
に挿入し、A
の依存関係をMyFragment.onActivityCreated
に挿入する必要があります。 2つの異なるコンポーネントを使用してみましたが、部分的な注入を実行できないようです。現在、私はMyFragment.onActivityCreated
にFragment A
依存関係の明示的な再割り当てを追加することになりましたが、それは実際には注入ではありません。これはもっと良い方法でできますか?
保持されたフラグメントの寿命がアクティビティよりも長いことを考えると、これを行う適切な方法はFragmentScope
にActivityScope
を含めることであり、その逆ではないことを期待します。
あなたのFragmentComponentが持つことを意味します
@FragmentScope
@Component(modules = {FragmentModule.class})
public interface FragmentComponent {
void inject(MyFragment presenter);
}
そしてあなたのアクティビティコンポーネントは
@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
注入クラスが依存関係として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();
}
}