其实动态创建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();