關於Dagger2 android 動態生成Fragment的問題
阿新 • • 發佈:2019-02-07
其實動態建立Fragment的流程並不複雜。
1. 網路獲取Fragment的個數。
2. 通過Component建立Fragment。
主要的問題在於:
1. 我想使用全域性AppComponent 中的ApiService等物件
2. 我的BaseFragment預設使用了Dagger android的注入處理,導致編譯失敗
解決方案
1.使用@SupComponent來提供構建,將subComponent放到AppComponent中即可 2.去掉子類Fragment中對 Dagger 的使用 ,去除掉Presenter中Dagger的使用。 Fragment中需要的物件通過在Module中setter過來。 Presenter中需要的物件,同理也是通過Module中傳遞過來。 使用@SubComponent 的原因是希望可以使用AppComponent中構建的 全域性物件 如: - ApiService 全域性的網路請求 - Repository 全域性的資料庫操作等。 原理:在Module中可以使用Dagger,通過註解直接獲取需要物件(AppComponent中的全域性物件), 並通過setter方法設定給Fragment或Presenter。
更改如下:
1. 去除了子類Fragment中Dagger2 android的注入
BaseFragment中程式碼如下:
@Override
public void onAttach(Context context) {
inject();
super.onAttach(context);
}
protected void inject() {
//主要就是去掉這行程式碼
AndroidSupportInjection.inject(this);
}
在NewsFragment 中如下處理
@Override
protected void inject() {
//去除 Dagger 的inject 通過 newInstance() 建立 Fragment
// super.inject();
}
2. 改變Presenter的注入方式
將原來的Dagger Inject的方式改為通過 Setter方法設定
- 改前
@Inject
NewsListContract.Presenter mPresenter;
- 改後
NewsListContract.Presenter mPresenter;
public void setPresenter(NewsListContract.Presenter presenter) {
this .mPresenter = presenter;
}
同理對於Fragment和Presenter中其他@Inject的物件也要使用Setter方法設定
3. 使用subComponent構建
使用@SubComponent 的原因是希望可以使用AppComponent中構建的 全域性物件 如:
- ApiService 全域性的網路請求
- Repository 全域性的資料庫操作等。
NewsComponent.java
@NewsScope
@Subcomponent(
modules = {
NewsListModule.class
}
)
public interface NewsComponent {
//想要的就是這個
List<NewsListFragment> getFragment();
}
注意subComponent使用要有 Scope
NewsScope.java
@Scope
@Retention(RetentionPolicy.RUNTIME)
public @interface NewsScope {
}
NewListModule.java
@Module
public class NewsListModule {
//通過從Activity中構建NewsComponent時傳入
private List<NewsClassify> classifyList;
public NewsListModule(List<NewsClassify> classifyList) {
this.classifyList = classifyList;
}
@Provides
@NewsScope
public List<NewsClassify> provideClassifyList() {
return classifyList;
}
@Provides
@NewsScope
List<NewsListFragment> getFragmentList(List<NewsClassify> classifyList, ApiService apiService) {
List<NewsListFragment> fragmentList = new ArrayList<>();
if (classifyList != null) {
for (int i = 0; i < classifyList.size(); i++) {
//手動建立Fragment,並設定 Presenter
String id = classifyList.get(i).getAcId();
NewsListFragment fragment = NewsListFragment.newInstance(id);
fragment.setPresenter(new NewsListPresenter(apiService,id));
fragmentList.add(fragment);
}
}
return fragmentList;
}
}
4. 在全域性的AppComponent中提供 NewsComponent
subComponent ( NewsComponent ) 就是在這個地方提供用於建立。
AppComponent.java
@Singleton
@Component(modules = {
ApplicationModule.class, //application
DBModule.class, //db
ActivityBindingModule.class, //activity 註冊類
AndroidSupportInjectionModule.class, //..
RetrofitModule.class, // 提供retrofit
RepositoryModule.class, //倉庫相關的類
ApiServiceModule.class // ApiService 提供類
})
public interface AppComponent extends AndroidInjector<BaseApplication> {
@Component.Builder
interface Builder {
@BindsInstance
AppComponent.Builder application(Application application);
AppComponent build();
}
NewsComponent plus(NewsListModule newsListModule);
}
5. Activity中的呼叫方式
網路獲取成功後根據獲取的 List <NewsClassify> newsClassifies 構建NewsListModule
再呼叫newsComponent的getFragment就可以獲取到 List <Fragment> 了
AppComponent appComponent = BaseApplication.getInstance().getAppComponent();
NewsComponent newsComponent = appComponent.plus(new NewsListModule(newsClassifies));
mFragments.addAll(newsComponent.getFragment());
mAdapter.notifyDataSetChanged();