手把手教你做开源项目MyMeiZi 一( RxJava + Retrofit)

转载请注明出处:
http://blog.csdn.net/u014163726
本文出自Wrh的博客

开篇闲扯

在16年回顾15年的自己发现自己真的变懒了也没有当初那种求知欲了,不知道是不是因为繁忙的工作和精神压力导致的,不过我想来想去还是决定重新振作起来,说句文艺的话 不忘初心,方得始终


RxJava

相信关于RxJava大家或多或少都有所了解,这里就不在详细的介绍RxJava,放上几个非常的棒的文章链接

深入浅出RxJava
给 Android 开发者的 RxJava 详解


Retrofit

一个非常棒的网络加载库,而且支持了RxJava
Retrofit 2.0:有史以来最大的改进
Retrofit


正片环节

开源项目MyMeiZi

手把手教你做开源项目MyMeiZi 一( RxJava + Retrofit)_第1张图片

作为详解的第一篇我们就先讲讲抓取网络数据以及使用RxJava能有哪些非常方便的功能.

我们所有数据都是由gank.io提供,ok那我们今天就来分析一下这个首页的构成,先导入我们今天的主角RxJava+Retrofit

compile 'io.reactivex:rxandroid:1.1.0'
compile 'io.reactivex:rxjava:1.1.0'
compile 'com.squareup.retrofit2:retrofit:2.0.0-beta3'
compile 'com.squareup.retrofit2:converter-gson:2.0.0-beta3'
compile 'com.squareup.retrofit2:adapter-rxjava:2.0.0-beta3'

1.使用Retrofit拉取数据

使用Retrofit请求API数据-codepath教程
我们这边也简单的介绍一下使用方式

        //baseUrl为域名 eg:http://gank.avosapps.com/api/
        //factory为使用的反序列化工具 本例使用的为Gson
        //CallAdapterFactory为执行机制 本例使用为RxJava
        mRetrofit = new Retrofit.Builder()
                .baseUrl(BaseService.BASE_API)
                .addConverterFactory(GsonConverterFactory.create())
                .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
                .build();

上面就是一个完整初始化Retrofit的过程了,接下来我们开始go起来


public interface GankIoService {
GET("data/{type}/10/{count}")
Observable homeResult(@Path("type") String type, @Path("count") int count);
}

Retrofit 可以利用接口,方法和注解参数(parameter annotations)来声明式定义一个请求.

GankIoService service = mRetrofit.create(GankIoService.class);

Observable observable = service.homeResult(all, 0);
  observable.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(new Subscriber() {
            @Override
            public void onCompleted() {

            }

            @Override
            public void onError(Throwable e) {

            }

            @Override
            public void onNext(GankIoModel gankIoModel) {

            }
        });

至此就是一个完整的使用RxJava+Retrofit的过程了,可能看上去没什么出奇的而且代码比起普通的方式来说还多了不少.
接下来才是重点!!!
接下来才是重点!!!
接下来才是重点!!!

2.使用RxJava操作符

ok,到现在为止看上去一切都平淡无奇,我们的数据顺利的被拿到

{
_id: "56ce83f8421aa910e89d4379",
_ns: "ganhuo",
createdAt: "2016-02-25T02:22:18Z",
desc: "2.25",
publishedAt: "2016-02-25T12:34:54Z",
type: "福利",
url: "http://ww4.sinaimg.cn/large/7a8aed7bjw1f1bdal8i3nj20f00lf77g.jpg",
used: true,
who: "张涵宇"
},
{
_id: "56ce83f8421aa910e89d437a",
_ns: "ganhuo",
createdAt: "2016-02-25T01:09:22Z",
desc: "功能更加完备的一个Mac微信客户端",
publishedAt: "2016-02-25T12:34:54Z",
type: "瞎推荐",
url: "https://github.com/geeeeeeeeek/electronic-wechat",
used: true,
who: "YJX"
}

发现问题了么,只有type为福利时url才是图片,这样的话我们的首页其他数据图片怎么办,不过幸好我们还可以根据传过去的参数来获得只是福利的数据.

Observable observable = service.homeResult(福利, 0);

这就意味着我们需要请求两次网络并把数据整合到一起,相信很多人也会经常碰到这种情况需要把不同情况的集合结合到一起

我们可能会想到这种写法

 Observable observable = service.homeResult(mLoadType, mCount);
        final Observable observableFuli = service.homeResult(BaseEnum.fuli.getValue(), mCount);

        observable.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(new Action1() {
            @Override
            public void call(final GankIoModel gankIoModel) {
                observableFuli.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(new Action1() {
                    @Override
                    public void call(GankIoModel gankIoModel2) {
                        int model1 = gankIoModel.getResults().size();
                        int model2 = gankIoModel2.getResults().size();
                        for (int i = 0; i < model1; i++) {
                            gankIoModel.getResults().get(i).setUrl(gankIoModel2.getResults().get(i).getUrl());
                        }

                    }
                });
            }
        });

但是这是个什么玩意,wtf,杂乱无章的代码混乱的处理,这种情况对我们代码的破坏是很大的,相信很多人都碰到,然后心里默默的骂一句cnm!!!!

这时候就到了该真正灵活使用RxJava的时候了,关于操作符的概念,可以看这篇博客.
深入浅出RxJava(二:操作符)

这种情况我们使用一个combineLatest操作符

手把手教你做开源项目MyMeiZi 一( RxJava + Retrofit)_第2张图片

combineLatest操作符把两个Observable产生的结果进行合并,合并的结果组成一个新的Observable,So我们的代码就可以精简成

Observable.combineLatest(observable, observableFuli, new Func2() {
            @Override
            public GankIoModel call(GankIoModel gankIoModel, GankIoModel gankIoModel2) {
                List resultsEntities = gankIoModel.getResults();
                for (int i = 0; i < resultsEntities.size(); i++) {
                    if (!resultsEntities.get(i).getType().equals(BaseEnum.fuli.getValue())) {
                        resultsEntities.get(i).setImageUrl(gankIoModel2.getResults().get(i).getUrl());
                    } else {
                        resultsEntities.get(i).setImageUrl(gankIoModel.getResults().get(i).getUrl());
                    }
                }
                return gankIoModel;
            }
        }).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(new LoadNetSubscriber());

链式结构就是RxJava最牛b的地方了

首页UI

好的既然获取数据的问题已经解决了,我们就开始搭界面吧,可以看到首页其实相当简单,一个RecyclerView,一个FloatingActionButton,一个Menu菜单.

1.Data Binding

RecyclerView绑定一个Adapter想必大家都已经很熟练了,不过我们今天采用Data Binding方式来绑定数据到UI,关于Data Binding详情可见官方指导,这里也给出几个地址供大家学习。
Data Binding(数据绑定)用户指南

 @Override
    protected ItemHolder onAdapterCreateViewHolder(ViewGroup viewGroup, int viewType) {
        MaterialFeedLayout feedLayout = new MaterialFeedLayout(mContext);
        ItemHolder itemHolder = new ItemHolder(feedLayout);
        return itemHolder;
    }

    @Override
    protected void onAdapterBindViewHolder(ItemHolder viewHolder, int position) {
        viewHolder.feedLayout.setData(mData.get(position));
    }
  private void initView(Context context) {
         LayoutInflater inflater = LayoutInflater.from(context);
        ViewHomeFeedBinding mBinding = ViewHomeFeedBinding.inflate(inflater, this, true);
    }

    public void setData(GankIoModel.ResultsEntity data) {
        mBinding.setGankio(data);
    }

是的你没有看错,只需要这么少的代码一切就已经搞定了,甚至不需要去findViewById了,这能减少相当多的开发时间,至于xml中的话我们也需要一些特殊处理

<layout xmlns:android="http://schemas.android.com/apk/res/android">
    <data>
        <variable
            name="gankio"
            type="com.meizi.wrh.mymeizi.model.GankIoModel.ResultsEntity" />
    data>
    layout>

更详细的介绍放在了之前介绍的博客中.

2.特殊效果FloatingButton

可以看到我们的button会随着我们向下滚动而收起,向上滚动弹出,这里我是直接照搬的在列表滚动的时候显示或者隐藏Toolbar

原理就是如果总的滚动距离超多了一定值,我们就根据其方向显示或者隐藏Toolbar(dy>0意味着下滚,dy<0意味着上滚)非常简单的代码但是带来的效果却非常好.

3.Menu菜单

这个应该没什么说的了~~(感觉我这整片博客啥也没说%>_<%)


<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item
        android:id="@+id/main_all_menu"
        android:icon="@drawable/ic_more_vert_white"
        android:showAsAction="always"
        android:title="All" />

    <item
        android:id="@+id/main_android_menu"
        android:showAsAction="never"
        android:title="Android" />

    <item
        android:id="@+id/main_ios_menu"
        android:showAsAction="never"
        android:title="IOS" />


    <item
        android:id="@+id/main_video_menu"
        android:showAsAction="never"
        android:title="休息视频" />

    <item
        android:id="@+id/main_expand_menu"
        android:showAsAction="never"
        android:title="拓展资源" />

    <item
        android:id="@+id/main_qianduan_menu"
        android:showAsAction="never"
        android:title="前端" />
menu>
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.main_menu, menu);
        return true;
    }

结束语

啊啊啊啊啊啊啊啊啊,这篇跟流水账一样的博客我自己读起来都没啥兴趣。。。久违的写篇博客热热手,逐渐回复下状态,谢谢大家!

项目源码

你可能感兴趣的:(手把手教你做开源项目MyMeiZi 一( RxJava + Retrofit))