Android使用RxJava+Retrofit2+Okhttp+MVP练习的APP

项目截图

 

 

这是我的目录结构

五步使用RxJava+Retrofit2+Okhttp+RxCache

第一步:导包

    compile 'io.reactivex:rxjava:1.1.8'
    compile 'io.reactivex:rxandroid:1.2.1'
    compile 'com.squareup.retrofit2:retrofit:2.0.0-beta4'
    compile 'com.squareup.retrofit2:converter-gson:2.0.0-beta4'
    compile 'com.squareup.retrofit2:adapter-rxjava:2.0.0-beta4'
    compile 'com.github.VictorAlbertos.RxCache:core:1.4.6'

  

第二步:新建API接口

public interface GanHuoService {

    @GET("data/{type}/{number}/{page}")
    Observable<DataResults> getDataResults(
            @Path("type") String type,
            @Path("number") int number,
            @Path("page") int page
    );
}

  

第三步:新建缓存接口
/**
 * 缓存API接口
 *
 * @LifeCache设置缓存过期时间. 如果没有设置@LifeCache , 数据将被永久缓存理除非你使用了 EvictProvider, EvictDynamicKey or EvictDynamicKeyGroup .
 * EvictProvider可以明确地清理清理所有缓存数据.
 * EvictDynamicKey可以明确地清理指定的数据 DynamicKey.
 * EvictDynamicKeyGroup 允许明确地清理一组特定的数据. DynamicKeyGroup.
 * DynamicKey驱逐与一个特定的键使用EvictDynamicKey相关的数据。比如分页,排序或筛选要求
 * DynamicKeyGroup。驱逐一组与key关联的数据,使用EvictDynamicKeyGroup。比如分页,排序或筛选要求
 */
public interface CacheProviders {
    //缓存时间 1天
    @LifeCache(duration = 7, timeUnit = TimeUnit.DAYS)
    Observable<Reply<List<DataResults>>> getHomeTypes(Observable observable, DynamicKey userName, EvictDynamicKey evictDynamicKey);

}

  

第四步:新建retrofit抽象类
 
public abstract class RetrofitUtils {

    private static Retrofit mRetrofit;
    private static OkHttpClient mOkHttpClient;

    /**
     * 获取Retrofit对象
     *
     * @return
     */
    protected static Retrofit getRetrofit() {

        if (null == mRetrofit) {

            if (null == mOkHttpClient) {
                mOkHttpClient = OkHttp3Utils.getOkHttpClient();
            }

            //Retrofit2后使用build设计模式
            mRetrofit = new Retrofit.Builder()
                    //设置服务器路径
                    .baseUrl(Constant.API_SERVER + "/")
                    //添加转化库,默认是Gson
                    .addConverterFactory(GsonConverterFactory.create())
                    //添加回调库,采用RxJava
                    .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
                    //设置使用okhttp网络请求
                    .client(mOkHttpClient)
                    .build();
        }

        return mRetrofit;
    }

}

  

第五步:新建HttpData类 用于统一管理请求
 
/*
 * 所有的请求数据的方法集中地
 * 根据MovieService的定义编写合适的方法
 * 其中observable是获取API数据
 * observableCahce获取缓存数据
 * new EvictDynamicKey(false) false使用缓存  true 加载数据不使用缓存
 */
public class HttpData extends RetrofitUtils {

    private static File cacheDirectory = FileUtil.getcacheDirectory();
    private static final CacheProviders providers = new RxCache.Builder()
            .persistence(cacheDirectory)
            .using(CacheProviders.class);
    protected static final GanHuoService service = getRetrofit().create(GanHuoService.class);

    private static class SingletonHolder {
        private static final HttpData INSTANCE = new HttpData();
    }

    public static HttpData getInstance() {
        return SingletonHolder.INSTANCE;
    }

    public void getHomeInfo(Observer<DataResults> observer,  boolean isUseCache,String type, int number, int page) {
        Observable observable= service.getDataResults(type,number,page);
        Observable observableCahce=providers.getHomeTypes(observable,new DynamicKey("首页"),new EvictDynamicKey(!isUseCache)).map(new HttpResultFuncCcche<List<DataResults>>());
        setSubscribe(observableCahce,observer);
    }

    /**
     * 插入观察者
     *
     * @param observable
     * @param observer
     * @param <T>
     */
    public static <T> void setSubscribe(Observable<T> observable, Observer<T> observer) {
        observable.subscribeOn(Schedulers.io())
                .subscribeOn(Schedulers.newThread())//子线程访问网络
                .observeOn(AndroidSchedulers.mainThread())//回调到主线程
                .subscribe(observer);
    }

    /**
     * 用来统一处理RxCacha的结果
     */
    private class HttpResultFuncCcche<T> implements Func1<Reply<T>, T> {

        @Override
        public T call(Reply<T> httpResult) {
            return httpResult.getData();
        }
    }

}

  

 
搭建完成,可以像这样请求数据,需要写到Model里面的
public class HomeFragmentModel {

    public void loadData(final OnLoadDataListListener listener,boolean isUseCache ,String type, int number, int page) {
        HttpData.getInstance().getHomeInfo(new Observer<DataResults>() {
            @Override
            public void onCompleted() {

            }

            @Override
            public void onError(Throwable e) {
                listener.onFailure(e);
            }

            @Override
            public void onNext(DataResults homeDto) {
                listener.onSuccess(homeDto);
            }
        }, isUseCache,type,number,page);
    }
} 
 

MVC (Model-View-Controller)

M是指逻辑模型,V是指视图模型,C则是控制器。一个逻辑模型可以对于多种视图模型
使用MVC的目的是将M和V的实现代码分离,方便扩展,便于以后的管理
从开发者的角度,MVC把应用程序的逻辑层与界面是完全分开的,最大的好处是:界面设计人员可以直接参与到界面开发,程序员就可以把精力放在逻辑层上。
虽然理论上可以实现,但实践起来还是感觉不能完全分开...
Android中也可以说采用了当前比较流行的MVC框架,在Android中: 
  1) 视图层(View):一般采用XML文件进行界面的描述,使用的时候可以非常方便的引入,但是用xml编写了,又需要在Acitvity声明并且实例化。
  2) 控制层(Controller):Android的控制层的重任通常落在了众多的Acitvity的肩上,要通过Activity交割Model业务逻辑层处理,这样做的另外一个原因是Android中的Acitivity的响应时间是5s,如果耗时的操作放在这里,程序就很容易被回收掉。
  3) 模型层(Model):对数据库的操作、对网络等的操作都应该在Model里面处理,当然对业务计算等操作也是必须放在的该层的。

MVP

MVP 就是基于MVC 的模式上的一个演化版本。在MVC模式中,Activity应该是属于View这一层。而实质上,它既承担了View,同时也包含一些Controller的东西在里面。随着项目的迭代更新,这对开发很不友好,耦合度也原来越高,项目越来越难维护,而MVP 就是解决这样的痛点。把Activity的View和Controller抽离出来就变成了View和Presenter。

MVP的优点:

  • 模型与视图完全分离,我们可以修改视图而不影响模型

  • 可以更高效地使用模型,因为所有的交互都发生在一个地方——Presenter内部

  • 我们可以将一个Presenter用于多个视图,而不需要改变Presenter的逻辑。这个特性非常的有用,因为视图的变化总是比模型的变化频繁。

  • 如果我们把逻辑放在Presenter中,那么我们就可以脱离用户接口来测试这些逻辑(单元测试)

首页是Model层:业务逻辑和实体模型,所以Model层我只放业务逻辑
public class HomeFragmentModel {

    public void loadData(final OnLoadDataListListener listener,boolean isUseCache ,String type, int number, int page) {
        HttpData.getInstance().getHomeInfo(new Observer<DataResults>() {
            @Override
            public void onCompleted() {

            }

            @Override
            public void onError(Throwable e) {
                listener.onFailure(e);
            }

            @Override
            public void onNext(DataResults homeDto) {
                listener.onSuccess(homeDto);
            }
        }, isUseCache,type,number,page);
    }
}
 
然后是view层: View 对应于Activity或者fragment,负责View的绘制以及与用户交互
public interface HomeFragmentView {
    //显示加载页
    void showProgress();
    //关闭加载页
    void hideProgress();
    //加载新数据
    void newDatas(DataResults data);
    //显示加载失败
    void showLoadFailMsg();

}

  

然后就是Presenter 负责完成View于Model间的交互
public class HomePresenter  implements OnLoadDataListListener<DataResults> {

    private HomeFragmentView mView;
    private HomeFragmentModel mModel;

    public HomePresenter(HomeFragmentView mView) {
        this.mView = mView;
        this.mModel=new HomeFragmentModel();
        mView.showProgress();
    }

    public void getDataResults(boolean isUseCache,String type, int number, int page) {
        mModel.loadData(this,isUseCache,type,number,page);
    }

    @Override
    public void onSuccess(DataResults data) {
        mView.newDatas(data);
        mView.hideProgress();
    }

    @Override
    public void onFailure(Throwable e) {
        Log.e("onFailure",e.toString());
        mView.showLoadFailMsg();
    }
}

  

最终回到Activity或者fragment
 
public class DiscoveryFragment extends BaseFragment implements HomeFragmentView {

     private HomePresenter homePresenter;

    @Override
    protected View initView(LayoutInflater inflater, ViewGroup container) {
        return inflater.inflate(R.layout.fragment_list, container, false);
    }

    @Override
    protected void initData(Bundle savedInstanceState) {
            homePresenter = new HomePresenter(this);
    }

    @Override
    protected void loadData() {
        getData(isFirst);
    }

    private void getData(boolean isUseCache) {
        switch (mTitle) {
            case "首页":
                if (isTop) {
                    NOW_PAGE_FI = 1;
                }
                homePresenter.getDataResults(isUseCache,"all", fi_num, NOW_PAGE_FI);
                break;
               }
    }

    @Override
    public void newDatas(DataResults dataResults) {
        if (dataResults.isError()) {
            Snackbar.make(recyclerview, "服务器出问题啦", Snackbar.LENGTH_SHORT).show();
        } else {
            if (mTitle.equals("干货")) {
                ganhuo_list = new ArrayList<>();
                ganhuo_list.addAll(dataResults.getResults());
            }
        }
    }

    private void clearAdapterResults() {
        switch (mTitle) {
            case "首页":
                partAdapter.getResults().clear();
                break;
            case "妹纸":
                girlyAdapter.getResults().clear();
                break;
        }
    }

    @Override
    public void showLoadFailMsg() {
        Snackbar.make(recyclerview, "网络不顺畅嘞,更新不了数据啦", Snackbar.LENGTH_SHORT).show();
    }

    @Override
    public void showProgress() {

    }

    @Override
    public void hideProgress() {

    }
}

  

项目地址,欢迎star:
 
 
 
 
 

Android使用RxJava+Retrofit2+Okhttp+MVP练习的APP的更多相关文章

  1. 学习RxJava+Retrofit+OkHttp+MVP的网络请求使用

    公司的大佬用的是这一套,那我这个菜鸟肯定要学习使用了. 我在网上找了很多文章,写的都很详细,比如 https://www.jianshu.com/u/5fd2523645da https://www. ...

  2. android打飞机游戏、MVP句子迷App、悬浮窗、RxJava+Retrofit、加载动画、定制计划App等源码

    Android精选源码 微信打飞机 android进度设置加载效果源码 Android新手引导库EasyGuide MVP-好看又好用的句子迷客户端 XFloatView 一个简易的悬浮窗实现方案 a ...

  3. Android 基于ijkplayer+Rxjava+Rxandroid+Retrofit2.0+MVP+Material Design的android万能播放器aaa

    MDPlayer万能播放器 MDPlayer,基于ijkplayer+Rxjava+Rxandroid+Retrofit2.0+MVP+Material Design的android万能播放器,可以播 ...

  4. Rxjava + retrofit + dagger2 + mvp搭建Android框架

    最近出去面试,总会被问到我们项目现在采用的什么开发框架,不过据我的经验网络框架(volley)+图片缓存(uIl)+数据库(orm)+mvp,不过现在这套框架比较好了,现在采用什么呢?Rxjava + ...

  5. Retrofit + RxJava + OkHttp 让网络请求变的简单-基础篇

    https://www.jianshu.com/p/5bc866b9cbb9 最近因为手头上的工作做完了,比较闲,想着做一些优化.看到以前用的那一套网络框架添加一个请求比较麻烦,并且比较难用,所以想改 ...

  6. okhttputils【 Android 一个改善的okHttp封装库】使用(三)

    版权声明:本文为HaiyuKing原创文章,转载请注明出处! 前言 这一篇主要讲一下将OkHttpUtils运用到mvp模式中. 数据请求地址:http://www.wanandroid.com/to ...

  7. RxJava+Retrofit+OkHttp,一步一步封装网络框架;

    使用RxJava+Retrofit+OkHttp,首先在build.gradle添加: compile 'com.squareup.okhttp3:okhttp:3.8.1' compile 'com ...

  8. okhttputils【 Android 一个改善的okHttp封装库】使用(一)

    版权声明:本文为HaiyuKing原创文章,转载请注明出处! 前言 本文使用的OKHttp封装库是张鸿洋(鸿神)写的,因为在项目中一直使用这个库,所以对于一些常用的请求方式都验证过,所以特此整理下. ...

  9. Android 使用RxJava实现一个发布/订阅事件总线

    1.简单介绍 1.1.发布/订阅事件主要用于网络请求的回调. 事件总线可以使Android各组件之间的通信变得简单,而且可以解耦. 其实RxJava实现事件总线和EventBus比较类似,他们都依据与 ...

随机推荐

  1. Nhibernate学习教程(2)-- 第一个NHibernate程序

    NHibernate之旅(2):第一个NHibernate程序 本节内容 开始使用NHibernate 1.获取NHibernate 2.建立数据库表 3.创建C#类库项目 4.设计Domain 4- ...

  2. 在数组a中,a[i]+a[j]=a[k],求a[k]的最大值,a[k]max——猎八哥fly

    在数组a中,a[i]+a[j]=a[k],求a[k]的最大值,a[k]max. 思路:将a中的数组两两相加,组成一个新的数组.并将新的数组和a数组进行sort排序.然后将a数组从大到小与新数组比较,如 ...

  3. 结对编程1 (四则运算基于GUI)

    https://git.coding.net/Luo_yujie/sizeyunsuan.app.git 201421123034 201421123032 1. 需求分析 这次作业新引用了语言选择, ...

  4. 团队作业8——第二次项目冲刺(Beta阶段)5.18

    1.当天站立式会议照片 会议内容: 本次会议为第一次会议 本次会议在陆大楼2楼召开,本次会议内容: ①:部署第二次敏捷冲刺的计划 ②:做第一天任务的详细分工 ③:规定完成时间是在第二天之前 ④:遇到困 ...

  5. 201521123039《Java程序设计》 第二周学习总结

    1.本周学习总结 答:上课老师介绍了Java基本的数据类型,需要注意的地方有:**java的整型数都为带符号数**,**byte类型范围(-127,128)太小,所以我们一般不使用byte型,byte ...

  6. 201521123117 《Java程序设计》第14周学习总结

    1. 本周学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结多数据库相关内容. 2. 书面作业 1. MySQL数据库基本操作 建立数据库,将自己的姓名.学号作为一条记录插入.(截图,需出现自 ...

  7. javascript:12种JavaScript MVC框架之比较

    Gordon L. Hempton是西雅图的一位黑客和设计师,他花费了几个月的时间研究和比较了12种流行的JavaScript MVC框架,并在博客中总结了每种框架的优缺点,最终的结果是,Ember. ...

  8. 启用Oracle中的scott用户

    启用Oracle中的scott用户 在Linux系统上安装Oracle服务器,有的不含有scott用户,有的scott用户被锁.下面是添加scott用户或解锁scott. 一. 验证scott用户是否 ...

  9. Python接口测试自动化说明及代码实例:含get、post、put、delete等方法

    一.接口说明文档 环境准备: 安装火狐 安装插件: httprequester https://addons.mozilla.org/en-US/firefox/addon/httprequester ...

  10. DAOFactory复用代码

    工厂设计模式 public class DaoFactory { private static final DaoFactory factory = new DaoFactory(); private ...