数据解析,view渲染
先放一张效果图。
从效果图可以看出,首页的数据模型有三种,
1.顶部的大图
2.每一栏的标题
3.每一栏的正文内容
需要分别定义三个model
1.GankTopImageItem --表示顶部的大图
2.GankHeaderItem --表示每一栏的标题
3.GankNormalItem --表示每一栏的正文内容
另外再定义一个父类GankItem,上述的三个model类都要继承与GankItem类
GankItem类 写个空方法就行了。
public interface GankItem { }
为什么要特地多加这么一个父类呢?
因为加上这么一个父类,你在保存数据的时候,
就可以用这么一行代码来声明list,不管是GankTopImageItem类型的,还是GankHeaderItem类型的,或者是GankNormalItem类型的model都可以直接添加到gankList中。
List<GankItem> gankList = new ArrayList<>();
具体代码如下
private List<GankItem> getGankList(DayData dayData) { if (dayData == null || dayData.results == null) { return null; } List<GankItem> gankList = new ArrayList<>(); if (null != dayData.results.welfareList && dayData.results.welfareList.size() > 0) { gankList.add(GankTopImageItem.newImageItem(dayData.results.welfareList.get(0))); } if (null != dayData.results.androidList && dayData.results.androidList.size() > 0) { gankList.add(new GankHeaderItem(GankType.ANDROID)); gankList.addAll(GankNormalItem.newGankList(dayData.results.androidList)); } if (null != dayData.results.iosList && dayData.results.iosList.size() > 0) { gankList.add(new GankHeaderItem(GankType.IOS)); gankList.addAll(GankNormalItem.newGankList(dayData.results.iosList)); } if (null != dayData.results.frontEndList && dayData.results.frontEndList.size() > 0) { gankList.add(new GankHeaderItem(GankType.FRONTEND)); gankList.addAll(GankNormalItem.newGankList(dayData.results.frontEndList)); } if (null != dayData.results.extraList && dayData.results.extraList.size() > 0) { gankList.add(new GankHeaderItem(GankType.EXTRA)); gankList.addAll(GankNormalItem.newGankList(dayData.results.extraList)); } if (null != dayData.results.casualList && dayData.results.casualList.size() > 0) { gankList.add(new GankHeaderItem(GankType.CASUAL)); gankList.addAll(GankNormalItem.newGankList(dayData.results.casualList)); } if (null != dayData.results.appList && dayData.results.appList.size() > 0) { gankList.add(new GankHeaderItem(GankType.APP)); gankList.addAll(GankNormalItem.newGankList(dayData.results.appList)); } if (null != dayData.results.videoList && dayData.results.videoList.size() > 0) { gankList.add(new GankHeaderItem(GankType.VIDEO)); gankList.addAll(GankNormalItem.newGankList(dayData.results.videoList)); } return gankList; }
这样写在给相应的Adapter传递数据的时候,只要把这个list赋值过去就能达到传递多个不同类型数据的效果了。
当然还有别的方式,甚至可以只定义一个model,只不过这样每个model要多些字段,难免有些浪费。
数据解析完成然后回调给view进行渲染就行了,
那么如何回调呢?当然是要采用接口了。
定义接口类
public interface OnDataChangeListener { void postChange(List<GankItem> gankItems); }
view中设置接口实现类
@Override public void onViewCreated(View view, Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); TodayGankActionCreator creator = new TodayGankActionCreator(); //设置接口实现类 creator.setDataChangeListener(this); //view从对应的Creator请求数据 creator.getTodayGank(); } //接收到参数,mAdapter设置参数,并刷新视图 @Override public void postChange(List<GankItem> gankItems) { mAdapter.refreshData(gankItems); mAdapter.notifyDataSetChanged(); }
TodayGankActionCreator类中
public void setDataChangeListener(OnDataChangeListener dataChangeListener) { this.dataChangeListener = dataChangeListener; } @Override public void call(List<GankItem> gankItems) { //数据处理正常时调用 dataChangeListener.postChange(gankItems); }
贴上完整代码
TodayGankFragment类
public class TodayGankFragment extends Fragment implements OnDataChangeListener, SwipeRefreshLayout.OnRefreshListener, GankListAdapter.OnItemClickListener { public static final String TAG = TodayGankFragment.class.getSimpleName(); public static TodayGankFragment newInstance() { return new TodayGankFragment(); } @Bind(R.id.refresh_layout) SwipeRefreshLayout vRefreshLayout; @Bind(R.id.recycler_view) RecyclerView vWelfareRecycler; private GankListAdapter mAdapter; @Nullable @Override public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { View rootView = inflater.inflate(R.layout.frag_today, container, false); ButterKnife.bind(this, rootView); vRefreshLayout.setColorSchemeResources(R.color.colorPrimary, R.color.colorPrimaryDark, R.color.colorAccent); vRefreshLayout.setOnRefreshListener(this); vWelfareRecycler.setLayoutManager(new LinearLayoutManager(getActivity())); vWelfareRecycler.setHasFixedSize(true); mAdapter = new GankListAdapter(this); mAdapter.setOnItemClickListener(this); vWelfareRecycler.setAdapter(mAdapter); return rootView; } @Override public void onViewCreated(View view, Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); TodayGankActionCreator creator = new TodayGankActionCreator(); //设置接口实现类 creator.setDataChangeListener(this); //view从对应的Creator请求数据 creator.getTodayGank(); } @Override public void postChange(List<GankItem> gankItems) { mAdapter.refreshData(gankItems); mAdapter.notifyDataSetChanged(); } @Override public void onRefresh() { } @Override public void onClickNormalItem(View view, GankNormalItem normalItem) { } @Override public void onClickGirlItem(View view, GankTopImageItem girlItem) { } }
GankListAdapter类
public class GankListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>{ private static final int VIEW_TYPE_NORMAL = 1; private static final int VIEW_TYPE_HEADER = 2; private static final int VIEW_TYPE_GIRL_IMAGE = 3; private Fragment mFragment; private List<GankItem> mItems; private OnItemClickListener mItemClickListener; public interface OnItemClickListener { void onClickNormalItem(View view, GankNormalItem normalItem); void onClickGirlItem(View view, GankTopImageItem girlItem); } public GankListAdapter(Fragment fragment) { mFragment = fragment; } public void refreshData(List<GankItem> list) { mItems = list; notifyDataSetChanged(); } public void setOnItemClickListener(OnItemClickListener clickListener) { mItemClickListener = clickListener; } @Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { switch (viewType) { case VIEW_TYPE_HEADER: return new CategoryHeaderViewHolder(parent); case VIEW_TYPE_NORMAL: return new NormalViewHolder(parent); case VIEW_TYPE_GIRL_IMAGE: return new GirlImageViewHolder(parent); } return null; } @Override public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { if(holder instanceof CategoryHeaderViewHolder) { CategoryHeaderViewHolder headerHolder = (CategoryHeaderViewHolder) holder; headerHolder.title.setText(((GankHeaderItem)mItems.get(position)).name); return; } if(holder instanceof NormalViewHolder) { NormalViewHolder normalHolder = (NormalViewHolder) holder; final GankNormalItem normalItem = (GankNormalItem) mItems.get(position); normalHolder.title.setText(getGankTitleStr(normalItem.desc, normalItem.who)); normalHolder.itemView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if(null != mItemClickListener) { mItemClickListener.onClickNormalItem(v, normalItem); } } }); return; } if(holder instanceof GirlImageViewHolder) { GirlImageViewHolder girlHolder = (GirlImageViewHolder) holder; final GankTopImageItem girlItem = (GankTopImageItem) mItems.get(position); Glide.with(mFragment) .load(girlItem.imgUrl) .placeholder(R.color.imageColorPlaceholder) .centerCrop() .into(girlHolder.girl_image); girlHolder.itemView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if(null != mItemClickListener) { mItemClickListener.onClickGirlItem(v, girlItem); } } }); } } @Override public int getItemViewType(int position) { GankItem gankItem = mItems.get(position); if(gankItem instanceof GankHeaderItem) { return VIEW_TYPE_HEADER; } if(gankItem instanceof GankTopImageItem) { return VIEW_TYPE_GIRL_IMAGE; } return VIEW_TYPE_NORMAL; } @Override public int getItemCount() { return null == mItems ? 0 : mItems.size(); } private CharSequence getGankTitleStr(String desc, String who) { if(TextUtils.isEmpty(who)) { return desc; } SpannableStringBuilder builder = new SpannableStringBuilder(desc); SpannableString spannableString = new SpannableString(" (" + who + ")"); spannableString.setSpan(new TextAppearanceSpan(AppUtil.getAppContext(), R.style.SummaryTextAppearance), 0, spannableString.length(), 0); builder.append(spannableString); return builder; } public static class CategoryHeaderViewHolder extends RecyclerView.ViewHolder { @Bind(R.id.category_title) TextView title; public CategoryHeaderViewHolder(ViewGroup parent) { super(LayoutInflater.from(parent.getContext()).inflate(R.layout.recycler_item_category_title, parent, false)); ButterKnife.bind(this, itemView); } } public static class NormalViewHolder extends RecyclerView.ViewHolder { @Bind(R.id.title) TextView title; public NormalViewHolder(ViewGroup parent) { super(LayoutInflater.from(parent.getContext()).inflate(R.layout.recycler_item_gank, parent, false)); ButterKnife.bind(this, itemView); } } public static class GirlImageViewHolder extends RecyclerView.ViewHolder { @Bind(R.id.girl_image) RatioImageView girl_image; public GirlImageViewHolder(ViewGroup parent) { super(LayoutInflater.from(parent.getContext()).inflate(R.layout.recycler_item_girl_imge, parent, false)); ButterKnife.bind(this, itemView); girl_image.setRatio(1.618f); } } }
TodayGankActionCreator类
public class TodayGankActionCreator { private OnDataChangeListener dataChangeListener; public void setDataChangeListener(OnDataChangeListener dataChangeListener) { this.dataChangeListener = dataChangeListener; } //定义数据转化模板 private static SimpleDateFormat sDataFormat = new SimpleDateFormat("yyyy-MM-dd", Locale.CHINA); public void getTodayGank() { //RxJava处理数据 HttpService.Factory.getGankService() .getDateHistory() .subscribeOn(Schedulers.io()) .filter(new Func1<DateData, Boolean>() { @Override public Boolean call(DateData dateData) { return (null != dateData && null != dateData.results && dateData.results.size() > 0);//接口请求成功,这边返回true } }) .map(new Func1<DateData, Calendar>() { @Override public Calendar call(DateData dateData) { Calendar calendar = Calendar.getInstance(Locale.CHINA); try { calendar.setTime(sDataFormat.parse(dateData.results.get(0))); //设置时间为最新一天,一般是今天 } catch (ParseException e) { e.printStackTrace(); calendar = null; } return calendar; } }) .flatMap(new Func1<Calendar, Observable<DayData>>() { @Override public Observable<DayData> call(Calendar calendar) { return HttpService.Factory.getGankService() //再次请求数据,获取当天的数据 .getDayGank(calendar.get(Calendar.YEAR), calendar.get(Calendar.MONTH) + 1, calendar.get(Calendar.DAY_OF_MONTH)); } }) .map(new Func1<DayData, List<GankItem>>() { @Override public List<GankItem> call(DayData dayData) { return getGankList(dayData); } }) .observeOn(AndroidSchedulers.mainThread()) .subscribe(new Action1<List<GankItem>>() { @Override public void call(List<GankItem> gankItems) { //数据处理正常时调用 dataChangeListener.postChange(gankItems); } }, new Action1<Throwable>() { @Override public void call(Throwable throwable) { //数据处理过程中报错时调用 } }); } private List<GankItem> getGankList(DayData dayData) { if (dayData == null || dayData.results == null) { return null; } List<GankItem> gankList = new ArrayList<>(); if (null != dayData.results.welfareList && dayData.results.welfareList.size() > 0) { gankList.add(GankTopImageItem.newImageItem(dayData.results.welfareList.get(0))); } if (null != dayData.results.androidList && dayData.results.androidList.size() > 0) { gankList.add(new GankHeaderItem(GankType.ANDROID)); gankList.addAll(GankNormalItem.newGankList(dayData.results.androidList)); } if (null != dayData.results.iosList && dayData.results.iosList.size() > 0) { gankList.add(new GankHeaderItem(GankType.IOS)); gankList.addAll(GankNormalItem.newGankList(dayData.results.iosList)); } if (null != dayData.results.frontEndList && dayData.results.frontEndList.size() > 0) { gankList.add(new GankHeaderItem(GankType.FRONTEND)); gankList.addAll(GankNormalItem.newGankList(dayData.results.frontEndList)); } if (null != dayData.results.extraList && dayData.results.extraList.size() > 0) { gankList.add(new GankHeaderItem(GankType.EXTRA)); gankList.addAll(GankNormalItem.newGankList(dayData.results.extraList)); } if (null != dayData.results.casualList && dayData.results.casualList.size() > 0) { gankList.add(new GankHeaderItem(GankType.CASUAL)); gankList.addAll(GankNormalItem.newGankList(dayData.results.casualList)); } if (null != dayData.results.appList && dayData.results.appList.size() > 0) { gankList.add(new GankHeaderItem(GankType.APP)); gankList.addAll(GankNormalItem.newGankList(dayData.results.appList)); } if (null != dayData.results.videoList && dayData.results.videoList.size() > 0) { gankList.add(new GankHeaderItem(GankType.VIDEO)); gankList.addAll(GankNormalItem.newGankList(dayData.results.videoList)); } return gankList; } }
数据能正常请求了,view也能正常渲染了。这就完了吗?
不,这才刚开始。
再看看Flux架构的流向图,view向ActionCreator请求数据之后,应该发出一个Action,让Dispatcher去更新对应的store,之后再渲染视图。
代码改造
ActionCreator ->Action
首先要定义一个特有的Action,用来携带传递的数据以及证明自己是什么类型的action
RxAction 类
public class RxAction { private final String type; private final ArrayMap<String, Object> data; RxAction(String type, ArrayMap<String, Object> data) { this.type = type; this.data = data; } public static Builder type(String type) { return new Builder().with(type); } public String getType() { return type; } public ArrayMap<String, Object> getData() { return data; } @SuppressWarnings("unchecked") public <T> T get(String tag) { return (T) data.get(tag); } //使用静态内部类的方式来构造对象 public static class Builder { private String type; private ArrayMap<String, Object> data; Builder with(String type) { if (type == null) { throw new IllegalArgumentException("Type may not be null."); } this.type = type; this.data = new ArrayMap<>(); return this; } public RxAction build() { if (type == null || type.isEmpty()) { throw new IllegalArgumentException("At least one key is required."); } return new RxAction(type, data); } } }
使用方式很简单
//声明Action的类型为Type RxAction rxAction=RxAction.type(Type).build(); //将需要传递的数据,以map形式存入,由于Value的类型是Object的,所以任何类型的数据都可以存入 rxAction.getData().put(Key,Value);
Aciton->Dispatch
Action定义好了,需要一个Dispatch派发器来将这个Action传入的相对于的store,这里的store相当于是一个数据仓库,也是view最终渲染的数据来源。
定义Dispatcher类
public class Dispatcher {
private static Dispatcher instance; private final RxBus bus; private ArrayMap<String, Subscription> rxActionMap; private ArrayMap<String, Subscription> rxStoreMap; private Dispatcher(RxBus bus) { this.bus = bus; this.rxActionMap = new ArrayMap<>(); this.rxStoreMap = new ArrayMap<>(); } public static synchronized Dispatcher getInstance(RxBus rxBus) { if (instance == null) instance = new Dispatcher(rxBus); return instance; } public <T extends RxActionDispatch> void subscribeRxStore(final T object) { final String tag = object.getClass().getSimpleName(); Subscription subscription = rxActionMap.get(tag); if (subscription == null || subscription.isUnsubscribed()) { rxActionMap.put(tag, bus.get().filter(new Func1<Object, Boolean>() { @Override public Boolean call(Object o) { return o instanceof RxAction; } }).subscribe(new Action1<Object>() { @Override public void call(Object o) { object.onRxAction((RxAction) o); } })); } } public <T extends RxViewDispatch> void subscribeRxView(final T object) { final String tag = object.getClass().getSimpleName(); Subscription subscription = rxStoreMap.get(tag); if (subscription == null || subscription.isUnsubscribed()) { rxStoreMap.put(tag, bus.get().filter(new Func1<Object, Boolean>() { @Override public Boolean call(Object o) { return o instanceof RxStoreChange; } }).subscribe(new Action1<Object>() { @Override public void call(Object o) { object.onRxStoreChanged((RxStoreChange) o); } })); } } public void postRxAction(final RxAction action) { bus.send(action); } public void postRxStoreChange(final RxStoreChange storeChange) { bus.send(storeChange); } }
Dispatcher类中有两个方法
subscribeRxStore();
subscribeRxView();
这两个方法都是起注册作用的,跟Android原生的广播有点类似。
比如程序执行发送了一个Action,那么这个Action发送给谁呢。你不事先声明别人肯定不知道,那最后就只能丢弃了。
所以在Action发送之前,你就要先做好映射,
A -ActionA,
B -ActionB.
这样当ActionA发出之后,才会知道自己要到A哪里去。
Dispatcher类中还有一个RxBus,这个RxBus相当于一个简单的事件总线,类似于EventBus,
RxBus类
public class RxBus { private static RxBus instance; private final Subject<Object, Object> bus = new SerializedSubject<>(PublishSubject.create()); private RxBus() { } public synchronized static RxBus getInstance() { if (instance == null) { instance = new RxBus(); } return instance; } //发送事件 public void send(Object o) { bus.onNext(o); } public Observable<Object> get() { return bus; } }
总结一点,RxBus中的Subject 继承了Observable类,同时又实现了Observer接口,所以Subject可以同时充当事件的发送者和接受者。
所以RxBus.send(Object)发送事件,RxBus.filter()...可以处理事件
再回过头来看Dispatcher
把subscribeRxStore()方法,和postRxAction()方法抽取出来
//在view 一般是activity或者fragment 调用subscribeRxStore方法之后,代码在执行到bus.get().filter() 时就不会接着往下执行了。 //等到postRxAction()把事件发送出去之后,bus.get()收到事件才会接着执行 public <T extends RxActionDispatch> void subscribeRxStore(final T object) { final String tag = object.getClass().getSimpleName(); Subscription subscription = rxActionMap.get(tag); if (subscription == null || subscription.isUnsubscribed()) { rxActionMap.put(tag, bus.get().filter(new Func1<Object, Boolean>() { @Override public Boolean call(Object o) { return o instanceof RxAction; } }).subscribe(new Action1<Object>() { @Override public void call(Object o) { object.onRxAction((RxAction) o); } })); } } public void postRxAction(final RxAction action) { bus.send(action); }
同样的道理subscribeRxView()和对应的postActionChange()也是差不多的作用
我知道这么说可能有很多人看不懂,贴一份流程图来解释一下。
1.Fragment注册subscribeRxStore 和subscribeRxView
2.Fragment调用对应的creator 获取数据
3.数据解析成功之后会发送Action 即postAction()
4.subscribeRxStore 会通知对应的store 作出修改
5.数据修改之后 发出通知 postActionChange
6.subscribeRxView 收到Action之后 refreshView
这样一解释,我相信大部分人都能懂了。
下面贴上对应的store的代码
public class TodayGankStore extends RxStore { //设置ID,分类用 public static final String ID = "TodayGankStore"; //保存数据用 private List<GankItem> mItems; public TodayGankStore(Dispatcher dispatcher) { super(dispatcher); } @Override public void onRxAction(RxAction action) { switch (action.getType()) { case ActionType.GET_TODAY_GANK: mItems = action.get(Key.DAY_GANK); break; default: return; } //数据变更,发出对应的Action,通知view刷新 postChange(new RxStoreChange(ID, action)); } public List<GankItem> getItems() { return mItems; } }
对应的fragment
//在store发出Action之后,最后会调用fragment中的onRxStoreChanged方法来重新渲染视图,到这里整个流程就结束了。 @Override public void onRxStoreChanged(@NonNull RxStoreChange change) { switch (change.getStoreId()) { case TodayGankStore.ID: vRefreshLayout.setRefreshing(false); mAdapter.refreshData(store.getItems()); mAdapter.notifyDataSetChanged(); break; } }
最后给上一张分包结构图,
分包结构图
action :发送各类的action
data : 数据模型
dispatcher :action的派发者
http : 网络请求
store : 数据仓库
ui :各类view
utils :帮助类
Dagger2的引入
Dagger2是一个依赖注入框架,那么dagger2能起什么作用呢?
简单点讲就是
dagger2会帮你维护好一些对象,你需要什么对象,可以直接问dagger2要,
当然前提是你已经按照dagger2的要求写了好这些依赖。
比如:像下图这种情况,你需要得到result,那你不得不像代码那样,先得到c对象,得到c对象,就需要得到b对象,需要得到a对象。
public class Dagger2Test{ private classA a; private classB b; private classC c; private String result; public void onCreate() { super.onCreate(); b=new classB(a); c=new classC(b); result=c.get(0); } }
而使用了dagger2的话,可以写成这样
public class Dagger2Test{ //一个直接得到c对象,然后在oncreate中一行代码搞定 @Inject classC c; private TestComponent mComponent; private String result; public void onCreate() { super.onCreate(); mComponent.inject(this); result=c.get(0); } }
Dagger2的引入
在config.gradle(不知道config.gradle如何来的,请看系列文章第0章)设置依赖
//版本号 daggerVersion = '2.2' javaxAnnotationVersion = '1.0' //远程依赖 dependencies = [ daggerCompiler: "com.google.dagger:dagger-compiler:${daggerVersion}", dagger: "com.google.dagger:dagger:${daggerVersion}", javaxAnnotation: "javax.annotation:jsr250-api:${javaxAnnotationVersion}" ]
build.gradle下
buildscript { repositories { jcenter() } dependencies { classpath 'com.android.tools.build:gradle:2.1.0' //加入dagger2的apt插件 classpath 'com.neenbedankt.gradle.plugins:android-apt:1.4' } }
app/build.gradle下
文件顶部
//引入dagger2 的apt插件 apply plugin: 'com.neenbedankt.android-apt' //添加依赖 apt dependency['daggerCompiler'] compile dependency['dagger'] compile dependency['javaxAnnotation']
做完上述的工作,dagger2就已经引入成功了。
在项目中使用
首先回顾一下在开源项目2中的代码,在事件的起点view,也就是TodayGankFragment中,有段代码是这样的!
@Override public void onViewCreated(View view, Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); RxFlux rxFlux = RxFlux.init(MyApplication.getApplication()); Dispatcher dispatcher = rxFlux.getDispatcher(); SubscriptionManager manager = rxFlux.getSubscriptionManager(); store = new TodayGankStore(dispatcher); dispatcher.subscribeRxStore(store); dispatcher.subscribeRxView(this); creator = new TodayGankActionCreator(dispatcher, manager); //view从对应的Creator请求数据 creator.getTodayGank(); }
上述代码中最重要的,不可或缺的,不能再缩减的代码有这么几句
//两个监听注册 dispatcher.subscribeRxStore(store); dispatcher.subscribeRxView(this); //view从对应的Creator请求数据 creator.getTodayGank();
两个subscribe监听注册,以及数据请求,数据请求是事件的起点,subscribe是为了之后的数据流转所必须的。
除了这三行代码,其他的变量和对象的声明都可以想办法放到别处,使得这段代码变得简洁。
这个时候Daggar2就可以排上用场了。
首先来整理下依赖,我们的需要的依赖对象或者变量有
RxFlux
dispatcher
manager
store
creator
一个有5个依赖,再根据业务逻辑将5个依赖划分一下,
RxFlux,dispatcher,manager这三个依赖属于全局型依赖,就是说很多地方都需要用的到的依赖。
而store和creator只是局部型依赖,所以单独处理。
全局依赖
定义一个AppComponent类,具体写法不在累述。
@Singleton @Component(modules = {AppModule.class}) public interface AppComponent { // Dispatcher getDispatcher(); SubscriptionManager getSubscriptManager(); }
AppComponent类提供Dispatcher和SubscriptionManager两个对象,具体的实现在AppModule类中
@Module public class AppModule { private final RxFlux mRxFlux; public AppModule(MyApplication application) { mApplication = application; //初始化RxFlux mRxFlux = RxFlux.init(application); } @Provides @Singleton Dispatcher provideDispatcher() { return mRxFlux.getDispatcher(); } @Provides @Singleton SubscriptionManager provideSubscriptManager() { return mRxFlux.getSubscriptionManager(); } }
构造函数里初始化RxFlux,然后借用RxFlux,初始化Dispatcher和SubscriptionManager对象。
调用:
在程序入口MyApplication中使用
public class MyApplication extends Application { private static AppComponent mAppComponent; @Override public void onCreate() { super.onCreate(); initInjector(); } private void initInjector() { mAppComponent = DaggerAppComponent.builder() .appModule(new AppModule(this)) .build(); } public static AppComponent getAppComponent() { return mAppComponent; } }
在MyApplication中initInjector()方法执行之后,RxFlux,Dispatcher和SubscriptionManager三个依赖对象就初始化成功了。
接下来还需要store和creator这两个依赖,
定义一个TodayGankFragmentComponent类
@PerActivity @Component(dependencies = {AppComponent.class}) public interface TodayGankFragmentComponent { void inject(TodayGankFragment todayGankFragment); }
PerActivity类,声明scope,不然会报错
@Scope @Retention(RUNTIME) public @interface PerActivity {}
在TodayGankFragment中,使用TodayGankFragmentComponent,注意appComponent的时候要把你之前定义好的appComponent对象传进去,
private void initInjector() { TodayGankFragmentComponent mComponent= DaggerTodayGankFragmentComponent.builder() .appComponent(MyApplication.getAppComponent()) .build(); mComponent.inject(this); }
这个时候你就可以很简单的声明对象了,
比如TodayGankStore类中,先在构造方法上加上@Inject注解,表示我能接受一个dispatcher参数,并提供一个TodayGankStore对象,而dispatcher这个对象在最开始的appComponent中就已经初始化完成,
@Inject public TodayGankStore(Dispatcher dispatcher) { super(dispatcher); }
在需求类中,即TodayGankFragment中,声明TodayGankStore对象store,这个store就是TodayGankStore所提供的,这中间的过程Dagger2会帮你处理。
@Inject TodayGankStore store;
单独解释一下@Inject这个注解的作用
1.标记在构造方法上,表示对象提供者
2.标记在目标类中,表示实例对象。
加入了dagger2之后,代码变化如下,
@Inject TodayGankStore mStore; @Inject TodayGankActionCreator mActionCreator; @Inject Dispatcher mDispatcher; @Override public void onViewCreated(View view, Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); //RxFlux rxFlux = RxFlux.init(MyApplication.getApplication()); //Dispatcher dispatcher = rxFlux.getDispatcher(); //SubscriptionManager manager = rxFlux.getSubscriptionManager(); //store = new TodayGankStore(dispatcher); //dispatcher.subscribeRxStore(store); //dispatcher.subscribeRxView(this); //creator = new TodayGankActionCreator(dispatcher, manager); //view从对应的Creator请求数据 //creator.getTodayGank(); mDispatcher.subscribeRxStore(mStore); mDispatcher.subscribeRxView(this); mActionCreator.getTodayGank(); }
注释的代码是没加Dagger2之前的,可以明显的看出依赖关系简单了很多,代码逻辑也清晰了许多。
Dagger2还是能够给代码带来挺大的变化的。
本来还想再写一点基类封装的内容,不过由于部分代码和业务逻辑关系比较紧,要写的话,内容还有不少。
所以留到下次再讲吧!