2017-02-13 26 views
0

我有一個MainActivity需要一個MeasurementFragment,它需要一個Converter。注入一個注入的片段(沒有重複的組件)

問題是:當在[1]處注入MesurementFragment時,其自身依賴關係converter[2]未被注入。

class MainActivity extends AppCompatActivity { 
    @Inject MeasurementFragment measureFrag; 

    @Override 
    protected void OnCreate(Bundle b){ 
     //[1]* 
     DaggerMainActivityComponent().create().inject(this); 
    } 
} 

有沒有一種方法有注射「級聯」,這樣,當measureFrag被注入converter注入?

我可以在構造函數([3])中創建DaggerMainActivityComponent的第二個實例並注入它,但這聽起來像個壞主意。

class MeasurementFragment extends Fragment { 

    // [2]* 
    @Inject Converter converter; 

    // required *empty* constructor 
    MeasrementFragment(){ 
     // [3]* 
    } 
} 

其他可能相關的代碼(組件和模塊):

@Component 
interface MainActivityComponent(){ 
    void inject(MainActivity ma); 
    void inject(MeasurementFragment mf); // << not used :(
} 

@Module 
class MainActivityModule{ 
    @Provides MeasurementFragment getMF(){ return new MeasurementFragment(); } 
    @Provides Converter getConverter(){ return new Converter(); } 
} 

是否有更好的設計來實現這一目標?

+0

您必須在[3]中將MeasurementFragment注入依賴關係圖中。我認爲這是唯一的方法。對於設計部分,您可以在MainActivity中創建DaggerMainActivityComponent對象,然後使用getter和setter訪問並注入片段。 –

+0

嘗試添加MeasurementFragment的默認構造函數,並使用Inject註釋。刪除你的void注入(MeasurementFragment mf);來自你的組件,以及你的模塊的MeasurementFragment的Provide方法。 – ootinii

回答

1

有時,當我們正在學習像匕首2依賴注入框架,誤解可以出現的new關鍵字和靜態工廠都不惜一切代價避免和每一個對象應注射。

在碎片的情況下,用於實例化的best practice是使用靜態工廠方法。儘管以前的DI框架Roboguice鼓勵將Fragments作爲Activity的屬性(@Inject MeasurementFragment mf)注入,但對於Dagger 2,嘗試不同的方法可能會更好。原因是我們需要與FragmentManager協調活動:

對於給定的活動,片段由FragmentManager處理。當調用活動onSaveInstanceState(Bundle outBundle)(例如,在低內存條件下),FragmentManager將在onCreate(Bundle savedInstanceState);內保存每個用於恢復的片段的實例狀態。

這就是爲什麼你經常在Android例子中看到:

if (savedInstanceState == null) { 
     // During initial setup, plug in the details fragment. 
     DetailsFragment details = new DetailsFragment(); 
     details.setArguments(getIntent().getExtras()); 
     getFragmentManager().beginTransaction().add(android.R.id.content, details).commit(); 
    } 

saveInstanceState == null的檢查的情況下,這個片段已經存在於FragmentManager。在從已保存實例狀態恢復活動的情況下,您可以使用:

fragmentManager.findFragmentByTag(String tag) 

可以獲取句柄。這意味着使用Dagger 2在活動內部簡單地注入片段屬性不足以解釋碎片和活動的複雜生命週期。

更好的方法可能是放棄您的活動中的Fragment屬性注入,並按照開發人員指南中的建議使用靜態工廠。然後,您將在碎片本身內注入碎片的依賴關係。事情是這樣的:

class MeasurementFragment extends Fragment { 

    @Inject Converter converter; 

    static MeasurementFragment instantiate() { 
     //if MeasurementFragment comes to require params in the future 
     //you can pass them in here and use setArguments(Bundle params); 
     return new MeasurementFragment(null); 
    } 

    MeasurementFragment(){ 
    } 

    @Override 
    public void onActivityCreated(Bundle savedInstanceState) { 
     super.onActivityCreated(savedInstanceState); 
     DaggerMainActivityComponent.builder() 
      .build() 
      .inject(this); 
    } 
} 

現在,當您在活動內MeasurementFragment使用fragmentManager.beginTransaction().add(),注入將在當Android系統已通過調用生命週期回調至onActivityCreated(Bundle bundle)提交執行。

這是你的活動可能是什麼樣子這種方法:

class MainActivity extends AppCompatActivity { 

    public static final String MEASUREMENT_FRAG = "MEASUREMENT_FRAG"; 

    MeasurementFragment measureFrag; 

    @Override 
    protected void OnCreate(Bundle b){ 
     super(b); 
     injectMembers(); 
     if (b == null) { 
      measureFrag = MeasurementFragment.instantiate(); 
      getFragmentManager().beginTransaction().add(R.id.frag_container, measureFrag, MEASUREMENT_FRAG).commit(); 
     } 
     else { 
      //frag is already instantiated and added to container 
      measureFrag = getFragmentManager().findFragmentByTag(MEASUREMENT_FRAG); 
     } 
    } 

    @VisibleForTesting 
    void injectMembers() { 
     DaggerMainActivityComponent().create().inject(this); 
    } 
} 

我在這裏列出的是方法注射成員內部的證明在這個流行Dagger 2 example on Github片段。更進一步的是讓片段儘可能輕量級,並完全避免在它們內部注入依賴關係,如Google Android Architecture Blueprint for Dagger 2所示。