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


    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:
     
  • 相关阅读:
    LeetCode100-相同的树
    LeetCode66-加一
    LeetCode102-二叉树的层序遍历
    dubbo协议端口
    http错误-413 Request Entity Too Large
    【Jeecg Vue】通过getAction的finally来最大程度避免影响主数据呈现
    图片压缩,用这个就够了
    信息数据安全,日常办公你就要注意这些!
    java笔记:流式编程 数组与List集合互转
    改状态,你会改吗?你真的会改吗?
  • 原文地址:https://www.cnblogs.com/sixrain/p/7675793.html
Copyright © 2020-2023  润新知