雞湯:養(yǎng)成一個(gè)好習(xí)慣需要很久蕉陋,打破這個(gè)習(xí)慣卻只需要一瞬間的念頭
接上一章的內(nèi)容,如果還沒看過的朋友摔握,
請(qǐng)到文章底部查看系列對(duì)應(yīng)文章
數(shù)據(jù)解析寄狼,view渲染
先放一張效果圖。
從效果圖可以看出氨淌,首頁(yè)的數(shù)據(jù)模型有三種泊愧,
1.頂部的大圖
2.每一欄的標(biāo)題
3.每一欄的正文內(nèi)容
需要分別定義三個(gè)model
1.GankTopImageItem --表示頂部的大圖
2.GankHeaderItem --表示每一欄的標(biāo)題
3.GankNormalItem --表示每一欄的正文內(nèi)容
另外再定義一個(gè)父類GankItem,上述的三個(gè)model類都要繼承與GankItem類
GankItem類 寫個(gè)空方法就行了盛正。
public interface GankItem {
}
為什么要特地多加這么一個(gè)父類呢删咱?
因?yàn)榧由线@么一個(gè)父類,你在保存數(shù)據(jù)的時(shí)候豪筝,
就可以用這么一行代碼來聲明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;
}
這樣寫在給相應(yīng)的Adapter傳遞數(shù)據(jù)的時(shí)候团搞,只要把這個(gè)list賦值過去就能達(dá)到傳遞多個(gè)不同類型數(shù)據(jù)的效果了。
當(dāng)然還有別的方式多艇,甚至可以只定義一個(gè)model逻恐,只不過這樣每個(gè)model要多些字段,難免有些浪費(fèi)峻黍。
數(shù)據(jù)解析完成然后回調(diào)給view進(jìn)行渲染就行了复隆,
那么如何回調(diào)呢?當(dāng)然是要采用接口了姆涩。
定義接口類
public interface OnDataChangeListener {
void postChange(List<GankItem> gankItems);
}
view中設(shè)置接口實(shí)現(xiàn)類
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
TodayGankActionCreator creator = new TodayGankActionCreator();
//設(shè)置接口實(shí)現(xiàn)類
creator.setDataChangeListener(this);
//view從對(duì)應(yīng)的Creator請(qǐng)求數(shù)據(jù)
creator.getTodayGank();
}
//接收到參數(shù)挽拂,mAdapter設(shè)置參數(shù),并刷新視圖
@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) {
//數(shù)據(jù)處理正常時(shí)調(diào)用
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();
//設(shè)置接口實(shí)現(xiàn)類
creator.setDataChangeListener(this);
//view從對(duì)應(yīng)的Creator請(qǐng)求數(shù)據(jù)
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;
}
//定義數(shù)據(jù)轉(zhuǎn)化模板
private static SimpleDateFormat sDataFormat = new SimpleDateFormat("yyyy-MM-dd", Locale.CHINA);
public void getTodayGank() {
//RxJava處理數(shù)據(jù)
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);//接口請(qǐng)求成功骨饿,這邊返回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))); //設(shè)置時(shí)間為最新一天亏栈,一般是今天
} 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() //再次請(qǐng)求數(shù)據(jù),獲取當(dāng)天的數(shù)據(jù)
.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) {
//數(shù)據(jù)處理正常時(shí)調(diào)用
dataChangeListener.postChange(gankItems);
}
}, new Action1<Throwable>() {
@Override
public void call(Throwable throwable) {
//數(shù)據(jù)處理過程中報(bào)錯(cuò)時(shí)調(diào)用
}
});
}
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;
}
}
數(shù)據(jù)能正常請(qǐng)求了样刷,view也能正常渲染了仑扑。這就完了嗎?
不置鼻,這才剛開始。
再看看Flux架構(gòu)的流向圖蜓竹,view向ActionCreator請(qǐng)求數(shù)據(jù)之后箕母,應(yīng)該發(fā)出一個(gè)Action,讓Dispatcher去更新對(duì)應(yīng)的store俱济,之后再渲染視圖嘶是。
代碼改造
ActionCreator ->Action
首先要定義一個(gè)特有的Action,用來攜帶傳遞的數(shù)據(jù)以及證明自己是什么類型的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);
}
//使用靜態(tài)內(nèi)部類的方式來構(gòu)造對(duì)象
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);
}
}
}
使用方式很簡(jiǎn)單
//聲明Action的類型為Type
RxAction rxAction=RxAction.type(Type).build();
//將需要傳遞的數(shù)據(jù)蛛碌,以map形式存入聂喇,由于Value的類型是Object的,所以任何類型的數(shù)據(jù)都可以存入
rxAction.getData().put(Key,Value);
Aciton->Dispatch
Action定義好了蔚携,需要一個(gè)Dispatch派發(fā)器來將這個(gè)Action傳入的相對(duì)于的store希太,這里的store相當(dāng)于是一個(gè)數(shù)據(jù)倉(cāng)庫(kù),也是view最終渲染的數(shù)據(jù)來源酝蜒。
定義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類中有兩個(gè)方法
subscribeRxStore();
subscribeRxView();
這兩個(gè)方法都是起注冊(cè)作用的誊辉,跟Android原生的廣播有點(diǎn)類似。
比如程序執(zhí)行發(fā)送了一個(gè)Action亡脑,那么這個(gè)Action發(fā)送給誰(shuí)呢堕澄。你不事先聲明別人肯定不知道邀跃,那最后就只能丟棄了。
所以在Action發(fā)送之前蛙紫,你就要先做好映射拍屑,
A -ActionA,
B -ActionB.
這樣當(dāng)ActionA發(fā)出之后,才會(huì)知道自己要到A哪里去坑傅。
Dispatcher類中還有一個(gè)RxBus丽涩,這個(gè)RxBus相當(dāng)于一個(gè)簡(jiǎn)單的事件總線,類似于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;
}
//發(fā)送事件
public void send(Object o) {
bus.onNext(o);
}
public Observable<Object> get() {
return bus;
}
}
總結(jié)一點(diǎn)矢渊,RxBus中的Subject 繼承了Observable類,同時(shí)又實(shí)現(xiàn)了Observer接口枉证,所以Subject可以同時(shí)充當(dāng)事件的發(fā)送者和接受者矮男。
所以RxBus.send(Object)發(fā)送事件,RxBus.filter()...可以處理事件
再回過頭來看Dispatcher
把subscribeRxStore()方法四敞,和postRxAction()方法抽取出來
//在view 一般是activity或者fragment 調(diào)用subscribeRxStore方法之后脓鹃,代碼在執(zhí)行到bus.get().filter() 時(shí)就不會(huì)接著往下執(zhí)行了。
//等到postRxAction()把事件發(fā)送出去之后博助,bus.get()收到事件才會(huì)接著執(zhí)行
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()和對(duì)應(yīng)的postActionChange()也是差不多的作用
我知道這么說可能有很多人看不懂秒赤,貼一份流程圖來解釋一下猪瞬。
1.Fragment注冊(cè)subscribeRxStore 和subscribeRxView
2.Fragment調(diào)用對(duì)應(yīng)的creator 獲取數(shù)據(jù)
3.數(shù)據(jù)解析成功之后會(huì)發(fā)送Action 即postAction()
4.subscribeRxStore 會(huì)通知對(duì)應(yīng)的store 作出修改
5.數(shù)據(jù)修改之后 發(fā)出通知 postActionChange
6.subscribeRxView 收到Action之后 refreshView
這樣一解釋,我相信大部分人都能懂了入篮。
下面貼上對(duì)應(yīng)的store的代碼
public class TodayGankStore extends RxStore {
//設(shè)置ID陈瘦,分類用
public static final String ID = "TodayGankStore";
//保存數(shù)據(jù)用
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;
}
//數(shù)據(jù)變更,發(fā)出對(duì)應(yīng)的Action潮售,通知view刷新
postChange(new RxStoreChange(ID, action));
}
public List<GankItem> getItems() {
return mItems;
}
}
對(duì)應(yīng)的fragment
//在store發(fā)出Action之后痊项,最后會(huì)調(diào)用fragment中的onRxStoreChanged方法來重新渲染視圖,到這里整個(gè)流程就結(jié)束了酥诽。
@Override
public void onRxStoreChanged(@NonNull RxStoreChange change) {
switch (change.getStoreId()) {
case TodayGankStore.ID:
vRefreshLayout.setRefreshing(false);
mAdapter.refreshData(store.getItems());
mAdapter.notifyDataSetChanged();
break;
}
}
最后給上一張分包結(jié)構(gòu)圖鞍泉,
action :發(fā)送各類的action
data : 數(shù)據(jù)模型
dispatcher :action的派發(fā)者
http : 網(wǎng)絡(luò)請(qǐng)求
store : 數(shù)據(jù)倉(cāng)庫(kù)
ui :各類view
utils :幫助類
本章先到這里,還剩下一部分內(nèi)容肮帐,包括基類的封裝以及Dagger的引入咖驮,留到下次再講。
相應(yīng)的代碼我會(huì)傳到github上训枢。
本人也只是Android開發(fā)路上一只稍大一點(diǎn)的菜鳥托修,如果各位讀者中發(fā)現(xiàn)文章中有誤之處,請(qǐng)幫忙指出肮砾,你的批評(píng)和鼓勵(lì)都是我前進(jìn)的動(dòng)力诀黍。
寫在文末:如果讀者朋友有什么問題或者意見可以在評(píng)論里指出.
代碼地址為https://github.com/niknowzcd/FluxDemo1