登录 立即注册
安币:

安卓巴士 - 安卓开发 - Android开发 - 安卓 - 移动互联网门户

从零开始搭建一个项目(rxJava+Retrofit+Dagger2) ---下 [复制链接]

2017-9-4 10:48
kengsirLi 阅读:1477 评论:2 赞:1
Tag:  

从零开始搭建一个项目(rxJava+Retrofit+Dagger2) ---上

http://www.apkbus.com/blog-873057-72598.html



数据解析,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还是能够给代码带来挺大的变化的。
本来还想再写一点基类封装的内容,不过由于部分代码和业务逻辑关系比较紧,要写的话,内容还有不少。
所以留到下次再讲吧!





分享到:
我来说两句
facelist
您需要登录后才可以评论 登录 | 立即注册
所有评论(2)
mimixi666 2017-9-7 15:53
如果有git源码分析,就更好了
回复
stronking 2017-9-19 13:50
mimixi666: 如果有git源码分析,就更好了
学习一个软件,主要是看思路。思路懂了,实现的方法自然而然的就在脑子里面呈现了。
回复

站长推荐

通过邮件订阅最新安卓weekly信息
上一条 /4 下一条

下载安卓巴士客户端

全国最大的安卓开发者社区

广告投放| 广东互联网违法和不良信息举报中心|中国互联网举报中心|下载客户端|申请友链|手机版|站点统计|安卓巴士 ( 粤ICP备15117877号 )

返回顶部