從零開始搭建一個(gè)項(xiàng)目(rxJava+Retrofit+Dagger2) --第2章

雞湯:養(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)圖鞍泉,

分包結(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上训枢。

從零開始系列第0章
從零開始系列第1章
從零開始系列第2章
從零開始系列完結(jié)章

本人也只是Android開發(fā)路上一只稍大一點(diǎn)的菜鳥托修,如果各位讀者中發(fā)現(xiàn)文章中有誤之處,請(qǐng)幫忙指出肮砾,你的批評(píng)和鼓勵(lì)都是我前進(jìn)的動(dòng)力诀黍。

寫在文末:如果讀者朋友有什么問題或者意見可以在評(píng)論里指出.
代碼地址為https://github.com/niknowzcd/FluxDemo1

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市仗处,隨后出現(xiàn)的幾起案子眯勾,更是在濱河造成了極大的恐慌枣宫,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,386評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件吃环,死亡現(xiàn)場(chǎng)離奇詭異也颤,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)郁轻,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,142評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門翅娶,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人好唯,你說我怎么就攤上這事竭沫。” “怎么了骑篙?”我有些...
    開封第一講書人閱讀 164,704評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵蜕提,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我靶端,道長(zhǎng)谎势,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,702評(píng)論 1 294
  • 正文 為了忘掉前任杨名,我火速辦了婚禮脏榆,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘台谍。我一直安慰自己须喂,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,716評(píng)論 6 392
  • 文/花漫 我一把揭開白布典唇。 她就那樣靜靜地躺著镊折,像睡著了一般。 火紅的嫁衣襯著肌膚如雪介衔。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,573評(píng)論 1 305
  • 那天骂因,我揣著相機(jī)與錄音炎咖,去河邊找鬼。 笑死寒波,一個(gè)胖子當(dāng)著我的面吹牛乘盼,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播俄烁,決...
    沈念sama閱讀 40,314評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼绸栅,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了页屠?” 一聲冷哼從身側(cè)響起粹胯,我...
    開封第一講書人閱讀 39,230評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤蓖柔,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后风纠,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體况鸣,經(jīng)...
    沈念sama閱讀 45,680評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,873評(píng)論 3 336
  • 正文 我和宋清朗相戀三年竹观,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了镐捧。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,991評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡臭增,死狀恐怖懂酱,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情誊抛,我是刑警寧澤列牺,帶...
    沈念sama閱讀 35,706評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站芍锚,受9級(jí)特大地震影響昔园,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜并炮,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,329評(píng)論 3 330
  • 文/蒙蒙 一默刚、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧逃魄,春花似錦荤西、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,910評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至癌瘾,卻和暖如春觅丰,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背妨退。 一陣腳步聲響...
    開封第一講書人閱讀 33,038評(píng)論 1 270
  • 我被黑心中介騙來泰國(guó)打工妇萄, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人咬荷。 一個(gè)月前我還...
    沈念sama閱讀 48,158評(píng)論 3 370
  • 正文 我出身青樓冠句,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親幸乒。 傳聞我的和親對(duì)象是個(gè)殘疾皇子懦底,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,941評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容