Android RxJava+Retrofit+MVP 入门总结

前言

RxJava+Retrofit+MVP的使用已经推出一段时间了,也一直想找个时间学习一下并且应用到接下来的项目中。趁放假这段时间仔细研究了一下,确实相比于其他框架的学习成本要高一些,不过功能实现之后的代码明显层次分明,整洁度较之前分明不少。

本文仅适合入门RxJava+Retrofit的同学用来学习参考,可能对于已经熟练掌握的读者参考价值不大,特此声明。

一.学习准备

本章节记录的为RxJava,Retrofit2,MVP设计模式的一些入门级资料,这些资料为笔者近段时间上网搜罗而来。

对于已经提前学习这些或者已经有所掌握的读者,您可以有选择性的查阅您感兴趣的资料查漏补缺,如果您认为已经有一定能力,可以选择跳过本节;

对于想要学习这些,却又不知何处下手的读者,建议您花一点时间学习这些资料;幸运的我们可以通过站在这些先行者前辈的肩膀上,系统进行学习,最高效率入门这门技术。

1.RxJava

<1>深入浅出RxJava(一:基础篇) @hi大头鬼hi

全系列共分4章,非常详细介绍了RxJava的使用,虽然是译文,但也可以看出作者十分用心,好评!
唯一一点就是原文作者加入了Lambda表达式,增加了一定的学习成本,但是私以为这样跟能让自己去自己通过思考敲出demo中的代码,反而增深了对rx的理解。

<2> 给 Android 开发者的 RxJava 详解 @扔物线

看完1中的4篇,再看本文就轻松许多,相对于上篇系列中的使用讲解,本文更倾向于阐述“为什么要用RxJava”的思想,获益良多。

2.Retrofit2.0

<1> 全新的网络加载框架Retrofit2,上位的小三 @戴定康

非常基础实用的Retrofit使用教程

<2>Retrofit2 完全解析 探索与okhttp之间的关系 @ 鸿洋_

鸿洋大神的精品之作,文章从基础的使用引申,通过源码向我们阐述了Retrofit2的实现原理,膜拜。

3 MVP+RxJava+Retrofit

<1>Android MVP+Retrofit+RxJava实践小结 @吴小龙同學

<2>Android中RxJava+Retrofit2.0+MVP模式的整合 @请叫我小东子

两篇相当精品的入门整合教程,对笔者的学习起着先导性的作用,本文也是整合了文中涉及知识点和笔者在实践中遇到坑及解决方案。

二.分包及依赖

分包:


分包及依赖

bean: 主要存放bean的实体类,供Gson解析为bean对象。
model:MVP中的M层,通过presenter初始化并调用处理数据。
presenter:MVP中的P层,像管家一样负责model和view的调用。
view:MVP中的V层,负责界面Ui的搭建。
retrofit:存放的是retrofit的接口以及对应的管理类。

dependencies:

compile ‘io.reactivex:rxjava:1.1.0’
compile ‘io.reactivex:rxandroid:1.1.0’
compile ‘com.squareup.retrofit2:retrofit:2.1.0’
compile ‘com.squareup.retrofit2:adapter-rxjava:2.1.0’//CallAdapterFactory的Rx依赖包
compile ‘com.squareup.retrofit2:converter-gson:2.1.0’
compile ‘com.squareup.retrofit2:converter-scalars:2.1.0’//ConverterFactory的String依赖包

建议放入个人本地的wiki中备忘,以便以后使用。

三.代码实现

ps:文中采用的数据接口来源于笔者公司的实际项目,故不在文中暴露接口及bean的实体类代码,有兴趣的可以下载代码或者参照代码使用自己的接口。

0.Retrofit接口及对应管理类

service接口

    public interface MainService {
        /**
         * 获取video数据  包括标题title,视频网络地址url等等
         * @param type  类型  3
         * @param showNum 要展示的数据个数 10
         * @return
         */
        @POST("getMediate/getMediate")
        @FormUrlEncoded
        Observable<VideoBean> getVideoBean(@Field("type") String type, @Field("showNum") String showNum);
    }

管理类,单例模式,通过getVideoBean()方法获得Observable对象在model中调用

public class MainServiceManager  {

        private static MainServiceManager manager;

        private MainService service;

        private MainServiceManager() {
            init();
        }

        public synchronized static MainServiceManager getInstance(){
            if(manager==null){
                manager=new MainServiceManager();
            }
            return  manager;
        }

        /**
         * 初始化资源
         */
        private void init() {
            Retrofit retrofit=new Retrofit.Builder()
                    .baseUrl(MainApi.BaseUrlVideo)
                    .addConverterFactory(GsonConverterFactory.create())
                    .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
                    .build();
            service = retrofit.create(MainService.class);
        }

        /**
         * 获取video数据列表
         * @return
         */
        public Observable<VideoBean> getVideoBean(String type,String showNum) {
            return service.getVideoBean(type,showNum);
        }
    }

1.MainActivity

MVP中V的实现类,负责处理的是界面的搭建,获得网络数据等逻辑交给presenter,让其调用model请求数据。

 public class MainActivity extends AppCompatActivity implements View.OnClickListener,MainActView {

    private Button mBtData;
    private ListView mListview;
    private MainPresenterImpl presenter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //xml文件中仅仅有一个button和一个listview
        setContentView(R.layout.activity_main);
        initView();
    }

    private void initView() {
        presenter = new MainPresenterImpl(this);
        presenter.attachView(this);         
        mBtData = (Button) findViewById(R.id.bt_data); //button
        mListview = (ListView) findViewById(R.id.listview);//listview
        mBtData.setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.bt_data:
                RequestUi();
                break;
        }
    }


    private void RequestUi() {
        presenter.requestData(String.valueOf(3),String.valueOf(12));
    }


    private ArrayList<String> datas=new ArrayList<>();

    //下面这个方法在model获得网络数据后由presenter调用
    @Override
    public void loadDatas(VideoBean videoBean) {
        if(videoBean==null){
            Toast.makeText(this,"加载数据失败,请检查网络!",Toast.LENGTH_SHORT).show();
            return;
        }
        ArrayList<VideoBean.ListBean> list = (ArrayList<VideoBean.ListBean>) videoBean.list;
        if(list.size()==0){
            Toast.makeText(this,"数据源没有数据!",Toast.LENGTH_SHORT).show();
            return;
        }
        Log.i("test","加载数据成功,已将数据传回mainActivity!!!======"+list.size());
        Log.i("test",list.toString());

        //下列代码为遍历数据源将,所有视频数据的标题作为item展示在listview上面
        for (int i=0;i<list.size();i++){
            datas.add(list.get(i).title);
            Log.i("test","datas["+i+"]====="+datas.size());
        }
        ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,android.R.layout.simple_list_item_1,android.R.id.text1,
                datas);
        mListview.setAdapter(adapter);
        //解除注册
        presenter.detachView();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        presenter.detachView(); //解除注册,防止内存泄漏,详见BasePresenter
    }
}

2.BasePresenter

通过使presenter继承BasePresenter,当presenter创建时在View层调用attachView方法绑定注册,当View层获得数据后或者销毁时调用detachView解除注册,防止内存泄漏。

public abstract class BasePresenter<V> {

    public V mvpView;
    private CompositeSubscription mCompositeSubscription;

    public void attachView(V mvpView) {
        this.mvpView = mvpView;
    }

    public void detachView() {
        this.mvpView = null;
        onUnsubscribe();
    }

    //RXjava取消注册,以避免内存泄露
    public void onUnsubscribe() {
        if (mCompositeSubscription != null && mCompositeSubscription.hasSubscriptions()) {
            mCompositeSubscription.unsubscribe();
            Log.i("test","Rx取消注册成功!");
            return;
        }
            Log.i("test","mCompositeSubscription判断为false");
    }

    public void addSubscription(Subscription subscriber) {
        if (mCompositeSubscription == null) {
            mCompositeSubscription = new CompositeSubscription();
        }
        mCompositeSubscription.add(subscriber);
    }
    }

3.PresenterImpl & Presenter接口类

Presenter接口类

public interface MainPresenter{

    /**
     * 请求网络数据
     */
    void requestData(String type,String showNum);

    /**
     * 数据请求成功
     * @param videoBean
     */
    void onSuccess(VideoBean videoBean);

    /**
     * 数据请求失败
     * @param throwable
     */
    void onFailure(Throwable throwable);
    }

PresenterImpl实现类

public class MainPresenterImpl extends BasePresenter implements MainPresenter {

    private  MainActView activity;
    private  MainModel model;

    public MainPresenterImpl(MainActView activity) {
        this.activity = activity;
        model = new MainModelImpl(this);
    }

    @Override
    public void requestData(String type, String showNum) {
        //请求网络数据,并且将Subscription作为返回值返回
        Subscription subscription = model.requestData(type, showNum);
        addSubscription(subscription);//Rx注册
    }

    @Override       //请求数据成功,调用View层的对应方法
    public void onSuccess(VideoBean videoBean) {
        activity.loadDatas(videoBean);
    }

    @Override       //请求数据失败,调用View层的对应方法并打印错误信息
    public void onFailure(Throwable throwable) {
        Log.e("test",throwable.toString());
        activity.loadDatas(null);
    }
    }

4.ModelImpl & Model接口类

Model接口类

public interface MainModel {

    /**
     * 请求数据
     * @param type
     * @param showNum
     */
    Subscription requestData(String type, String showNum);
    }

Model实现类

public class MainModelImpl implements MainModel {

    private MainPresenterImpl presenter;
    private Subscription subscribe;

    public MainModelImpl(MainPresenter mainPresenter) {
        //获得presenter对象
        this.presenter = (MainPresenterImpl) mainPresenter;
    }

    @Override
    public Subscription requestData(String type, String showNum) {
        //获得管理类对象
        MainServiceManager manager=MainServiceManager.getInstance();
        //RxJava代码
        Observable<VideoBean> observable =  manager.getVideoBean(type, showNum);
        subscribe = observable
                .observeOn(AndroidSchedulers.mainThread())
                .subscribeOn(Schedulers.io())
                .subscribe(new Subscriber<VideoBean>() {
                    @Override
                    public void onCompleted() {
                    }

                    @Override
                    public void onError(Throwable e) {
                    }

                    @Override
                    public void onNext(VideoBean videoBean) {
                        Log.i("test", "model onNext!!!===" + videoBean.list.toString());
                        presenter.onSuccess(videoBean);//获得数据,presenter调用onSuccess()
                    }
                });
            return subscribe;//返回给presenter
        }
    }

跳坑笔记(不断完善中)

1.一定要保证导入的retrofit2包的版本必须要一致,否则就会报错。

总结

项目完成后效果如下:

源码地址:

Demo源码地址

另:下为笔者自己采用了Dagger2+Rx+Retrofit+MVP的框架的一个APP源代码地址

LifeManager-Android

如果您觉得这个demo对您的Android开发学习和借鉴有所参考作用,望请不吝star,多谢!

应用中采用的框架(持续更新中):

单元测试 Junit+Mockito

ORM数据库 DBFlow

依赖注入 dagger2

联网请求 Rx+Retrofit

图片加载 Glide

其他好用并收录应用的库:

compile ‘org.greenrobot:eventbus:3.0.0’ //eventBus

compile ‘com.ashokvarma.android:bottom-navigation-bar:1.2.0’ //底部导航

compile ‘com.github.GrenderG:Toasty:1.1.5’ //不错的第三方Toast

compile ‘com.liaoinstan.springview:library:1.2.6’ //下拉刷新/上拉加载控件,内含多种流行App的UI效果

compile ‘com.lzy.widget:imagepicker:0.5.4’ //好用的图片选择器,高仿微信图片选择/拍照

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值