Android 使用RxJava+Retrofit +Realm 组合加载数据 (一)

如题解决方案直接从中间开始读起,上面都是废话

Rxjava 最近很流行,我也跟上潮流开始学习这个… 这个很牛逼的流式编程
什么 异步, 观察者模式, 响应式变成. 方法连 Observable Observer Subscribe 事件
OMG 各种概念.各种的各种..都是什么鬼..看的头都大了.目前还处于混乱期.
只明白了一点.这东西Rxjava上手确实不是那么容易的,各种参考资料,文档 各种的各种.

给 Android 开发者的 RxJava 详解
ReactiveX/RxJava文档中文版
RxJava适用场景小结
深入浅出RxJava(一:基础篇)
深入浅出RxJava ( 二:操作符 )
深入浅出RxJava ( 三–响应式的好处 )
深入浅出RxJava ( 四-在Android中使用响应式编程 )

github 上一些相关的资源

Awesome-RxJava 大部分的资料我是也是在这里找到的
RxJava 官方的开源地址
RxAndroid android平台相关
RxPermissions Rx配套的 6.0的权限申请
RxBinding JakeWharton大神的 控件绑定的一些支持库 什么防抖动之类的
RxLifecycle 防止内存泄漏的
….更多的请自行google寻找. 梯子Host 请低调使用

上面的资料,我居然都看了一边,有些不只一遍…可是还是懵懵懂懂. 感谢这些资料的总结者,给我这种小白提供入门的机会.虽然我资质有限,还没入门.
但是通过这几天的摸索.多少还是理解了一些.虽然有限.比如: 简化逻辑.不需要在写一堆异步回调的接口.便捷的线程切换等一些简单的概念.开始的时候,简单的集成到项目中,还是很顺利的,因为不久前就把项目中的网络模块替换成了Retrofit + okHttp.所以集成Rxjava需要添加一些相关的依赖就可以了

compile ‘com.squareup.retrofit2:adapter-rxjava:2.1.0’
compile ‘com.tbruyelle.rxpermissions:rxpermissions:0.7.0@aar’ //不是必须 6.0以上的权限申请
compile ‘io.reactivex:rxandroid:1.2.1’
compile ‘io.reactivex:rxjava:1.1.6’

WebApiServices 接口改造

public interface WebApiServices {

    @POST("/chaiche/api/recommend/home/")
    Observable getRecommendHomeDatas();//把call 换成Observable 就可以了
}

Activity调用

 RetrofitManager.getWebApiService()
                .getRecommendHomeDatas()
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Action1() {
                    @Override
                    public void call(RecommendHome recommendHome) {
                        setAdapter(recommendHome);
                    }
                });

完成后部署测试,没crash 说明没问题.

对比Retrofit Call + CallBack形式的


        Call call = RetrofitManager.getWebApiService().getRecommendHome();
        call.enqueue(new Callback() {
            @Override
            public void onResponse(Call call, Response response) {
                if (response.isSuccessful()) {
                    RecommendHome recommend = response.body();
                    setAdapter(recommend);
                }else{
                    //TODO
                }
            }

            @Override
            public void onFailure(Call call, Throwable t) {
                ToastManager.showShort(getActivity(),R.string.net_error);
            }
        });

好吧 .我承认.代码量确实没变化多少.可是,有没有感觉有那么一点点清晰?说白了就是好看了很多?有木有?

进一步的改进 创建NetManager ,封装请求管理.把网络请求方法和Activity/Fragment解耦,这样做的好处就是如果想替换网络请求框架了 不需要在动Activity/Fragment中调用网络请求的代码了

public class NetManager {

    //在访问HttpMethods时创建单例
    //这个单利据说是利用一个什么类加载器的原理.貌似这个,是线程安全的.感兴趣的话自行百度一下
    private static class SingletonHolder {
        private static final NetManager INSTANCE = new NetManager();
    }

    //获取单例
    @org.jetbrains.annotations.Contract(pure = true)
    public static NetManager getInstance() {
        return SingletonHolder.INSTANCE;
    }

    public void getRecommendDataSource(Subscriber subscriber) {
        RetrofitManager.getWebApiService()
                .getRecommendHomeDatas()
                .subscribeOn(Schedulers.io())
                .unsubscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(subscriber);
    }
}

调用 这里需要强调一下 不能使用一个Subscriber 否者第二次调用绝对不会得到返回值. 不信你可以试试

private Subscriber subscriber;  
private void requestHomeData() {
        subscriber = new Subscriber() {
            @Override
            public void onCompleted() {
                LogUtils.w(TAG, "subscriber onCompleted");
            }

            @Override
            public void onError(Throwable e) {
                LogUtils.w(TAG, "subscriber onError");
                ToastManager.showShort(getActivity(),R.string.net_error);
            }

            @Override
            public void onNext(RecommendHome recommendHome) {
                LogUtils.w(TAG, "subscriber onNext");
                if (recommendHome == null) {
                    mListView.setEmptyView(img_noData);
                } else {
                    setAdapter(recommendHome);
                }
            }
        };
        NetManager.getInstance().getRecommendDataSource(subscriber);
    }



    @Override
    public void onDestroy() {
        super.onDestroy();
        if (subscriber.isUnsubscribed()) { //不知道有没有用..反正我是先加上了
            subscriber.unsubscribe();
        }
    }

说道这里.其实这些只是初步的集成 调用. 如果想知道如题所说,以上都是废话

这样的过程

读取缓存 显示 请求网络数据 缓存最新数据 更新界面

我想做到的就是这么个过程,各种百度 google 文档等 能让我看懂理解的不多…不多 资质啊资质, 蛋蛋的忧伤飘过…….

找到的是使用

concat 操作符 说白了 就是把2个或者多个Observable连起来,按顺序执行,反正我是这么理解的

实现过程参考从零开始的Android新项目5 - Repository层(上) Retrofit、Repository组装 感谢博主提供的思想

代码如下 PS : 根据资料参考,写的demo .目的是总结一下实现过程. Copy 直接可在Activity/Fragment调用

  private void test_15() {

        final Observable fromDb = Observable.create(
                new Observable.OnSubscribe() {
                    @Override
                    public void call(Subscribersuper String> subscriber) {
                        String s = queryFormDb();
                        if (!s.equals("")) {
//                            System.out.println("fromDb  onNext");
                            subscriber.onNext(s);
                        }
                        subscriber.onCompleted();
                    }
                })
                .map(new Func1() {
                    @Override
                    public String call(String s) {
//                        System.out.println("fromDb  map call");
                        Logger.w(s);
                        return s;
                    }
                })
                .subscribeOn(Schedulers.io());

        //                .filter(new Func1() {
//                    @Override
//                    public Boolean call(String s) {
//                        return s.equals("");
//                    }
//                });
        final Observable fromNet = Observable.create(
                new Observable.OnSubscribe() {
                    @Override
                    public void call(Subscribersuper String> subscriber) {
                        String s = requestFromNet();
                        if (!s.equals("")) {
//                            System.out.println("fromNet  onNext");
                            subscriber.onNext(s);
                        }
                        subscriber.onCompleted();
                    }
                })
                .map(new Func1() {
                    @Override
                    public String call(String s) {
//                        System.out.println("fromNet  map call");
                        return s;
                    }
                })
                .doOnNext(new Action1() {
                    @Override
                    public void call(String s) {
                        if (!s.equals("")) {
//                            System.out.println("fromNet doOnNext call");
//                            System.out.println(s + "存入数据库");
                            Logger.w(s + "存入数据库");
                        }
                    }
                })
                .subscribeOn(Schedulers.io());
        Observable.concat(fromDb, fromNet)
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Action1() {
                               @Override
                               public void call(String s) {
                                   System.out.println(s);
                                   Logger.w(s);
                               }
                           },
                        new Action1() {
                            @Override
                            public void call(Throwable throwable) {
                                System.out.println(throwable.toString());
                                System.out.println(throwable.toString());
                            }
                        });
    }


    public String queryFormDb() {

        return "来自数据库的数据";
    }

    public String requestFromNet() {
        try {
            Thread.sleep(2000); //模拟网络请求耗时操作 延时2秒
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return "来自网络的数据";
    }

Log如下

╔══════════════════════════════════════════════════════════ W/PRETTYLOGGER: ║ Thread: RxIoScheduler-2
W/PRETTYLOGGER: ║  (LaunchActivity.java:93)
W/PRETTYLOGGER: ║    LaunchActivity$1.call   
W/PRETTYLOGGER: ║ 来自数据库的数据
╚══════════════════════════════════════════════════════════
╔══════════════════════════════════════════════════════════
W/PRETTYLOGGER: ║ Thread: main
W/PRETTYLOGGER: ║ LaunchActivity$6.call  (LaunchActivity.java:141)
W/PRETTYLOGGER: ║    LaunchActivity$6.call  (LaunchActivity.java:145)
W/PRETTYLOGGER: ║ 显示来自数据库的数据
╚══════════════════════════════════════════════════════════
╔══════════════════════════════════════════════════════════
W/PRETTYLOGGER: ║ Thread: RxIoScheduler-2
W/PRETTYLOGGER: ║ LaunchActivity$3.call  (LaunchActivity.java:128)
W/PRETTYLOGGER: ║    LaunchActivity$3.call  (LaunchActivity.java:134)
W/PRETTYLOGGER: ║ 来自网络的数据存入数据库
╚══════════════════════════════════════════════════════════
╔══════════════════════════════════════════════════════════ W/PRETTYLOGGER: ║ Thread: main
W/PRETTYLOGGER: ║ LaunchActivity$6.call  (LaunchActivity.java:141)
W/PRETTYLOGGER: ║    LaunchActivity$6.call  (LaunchActivity.java:145)
W/PRETTYLOGGER: ║ 显示来自网络的数据
╚══════════════════════════════════════════════════════════

另一种实现方式使用Rx同步并缓存网络数据

通过关联PublishSubject, 在插入数据完成后, 调用绑定观察者, 更新页面.
即.concatWith(mPublishSubject)和mPublishSubject.onNext(repos).

鉴于我还处于懵懵懂懂的状态.原谅我没太看明白.总结到这.我要把我上面贴出来的方法应用到我的项目中了.祝我成功

再次感谢以上总结资料的各位大神.

文笔有限,如有问题欢迎指正.如果你有更好的实现方法,欢迎留言交流,不过不要用Retrolambda 风格的.虽然简化,不过不适合学习中的我…

你可能感兴趣的:(开发笔记)