2017-09-01 72 views
0

我用匕首注入一個ViewModel成片段之前:匕首2:注射對象可能仍然爲空onAttach在片段稱爲

class BaseFragment<T extends BaseViewModel> extends Fragment { 

    @Inject T viewModel; 

    @Override 
    public void onAttach(Context context) { 
     super.onAttach(context); 
     if(viewModel == null) { 
      throw new RuntimeException("Viewmodel was null: "+getClass()); 
     } 
     viewModel.setContext(context); 
     viewModel.onAttach(context); 
    } 

} 

class MyFragment extends BaseFragment<MyViewModel> { 

    public MyFragment() { 
     MyApp.getInstance().getComponent().inject(this); 
     //viewModel should be available at this point, before OnAttach is called 
    } 

} 

因此,在短期我注入視圖模型在構造函數中,如果它在onAttach仍然是空的東西是錯誤的。

這絕不會發生,除非是100000次中的1次。只是幾個崩潰。但無法弄清楚爲什麼。這種方法是錯誤的嗎? Dagger是否對參數化對象有問題?

我不直接實例化BaseFragment,因此類型應該可以工作,它通常會這樣做,那麼爲什麼它在某些情況下不起作用?

+0

因此,有時'if(viewModel == null)'計算爲'true'? – azizbekian

+0

是的。非常稀有。 – breakline

回答

2

在一個片段的構造注射不正確:

public MyFragment() { 
    //MyApp.getInstance().getComponent().inject(this);  
    //don't inject in a constructor! 
} 

雖然這對於一個非常簡單的工作流程的工作,它不會正確處理片段生命週期。特別是,存在片段存在但與活動分離的情況。當發生這種情況並且需要向再次用戶顯示片段時,Android OS將嘗試重新附加緩存的片段而不調用構造函數(因爲實例已經存在)。由於您所依賴的假設是構造函數始終在onAttach之前被稱爲,所以可以想象,這種情況正在導致您的崩潰。

雖然可能很難在與您的應用程序正常交互的情況下自行復制此問題,但我懷疑如果您打開了System/DeveloperOptions/Don't keep activities測試應用程序,您會更有可能遇到它。

注入片段的子類的正確的方法是在onAttach(Context context)

@Override 
public void onAttach(Context context) { 
    MyApp.getInstance().getComponent().inject(this); 
    super(context); //call super 
} 

這將更加準確地跟蹤片段的生命週期。

請注意super呼叫之前的注射請求。這是根據Dagger official documentation中的建議。

+0

片段重新連接時會發生什麼?我想避免在可以多次調用的方法中注入事物 – breakline

+0

@breakline對不起,但對於Android活動和片段,除了在生命週期回調('onAttach'等)中插入註釋,如果您希望自己的應用程序正確處理生命週期。對於其他類,歡迎使用構造函數注入,這是首選。 –