天天看点

Android RxJava+Retrofit2.0+MVP的小试牛刀

这篇文章主要介绍Android Rxjava和Retrofit在MVP设计模式中的使用

Rxjava封装了异步操作,不用再写烦人的Handler,AsyncTask 让代码更简洁,逻辑更清晰,程序逻辑越复杂,Rxjava更能体现作用。

Retrofit是一个封装了网络操作的开源库

MVP设计模式就是使程序各个模块各司其职,互不干扰

View层专门负责与用户交互,逻辑处理不用管

Model层专门负责逻辑处理,你来个萝卜我就给你做成萝卜干,来个白菜就给你做成韩国泡菜

Presenter主要负责连接Model和View的,我的理解就是搬运工,Presenter把View(Activity)送过来的萝卜给Model,Model做好的萝卜干通过Presenter返回给View

道理很简单,都会说,但是真要实现起来还是有一定难得的,MVP难得就是一个思想,接口的定义,方法的回调都是比较抽象的,这需要不断地学习,多写多看。

在这里我就不单独介绍Rxjava和Retrofit这两个开源库了,网上有大把的博客

想学Rxjava的同学可以从这进入http://gank.io/post/560e15be2dca930e00da1083

想学Retrofit的同学请看这http://square.github.io/retrofit/

下面正式开始介绍如何使用RxJava+Retrofit2.0+MVP实现一个网络请求

首先,把需要用到的开源库在build.gradle中搞下来,这个例子中会用到

retrofit,Rxjava,okhttp,RxAndroid,Gson,SmartRefreshLayout,glide这些开源库

compile 'com.android.support:appcompat-v7:25.3.1'

compile 'com.android.support:recyclerview-v7:23.4.0'

compile 'com.squareup.retrofit2:retrofit:2.3.0' 

compile 'com.squareup.retrofit2:converter-gson:2.0.2'

compile 'com.squareup.retrofit2:adapter-rxjava:2.0.2'
           
compile 'com.squareup.okhttp3:okhttp:3.3.1' 网络请求的,retrofit主要是封装了请求操作,网络获取数据还是靠okhttp

compile 'com.scwang.smartrefresh:SmartRefreshLayout:1.0.3'

compile 'io.reactivex:rxandroid:1.1.0'

compile 'com.github.bumptech.glide:glide:4.0.0'
           

需要的开源库都准备好了,接下来可以开始干活了。既然用到了mvp设计模式,那样就不能像平时那样上来就开始在activity中写代码了,先得把架构打起来,然后再慢慢填充内容,就像建房子一样,一步一步来。先把包建好,这个自由发挥,没有固定的模式,看起来一目了然就行了,别后期找个类都要找半天,不晓得在哪个包里面,还得一个一个的看

Android RxJava+Retrofit2.0+MVP的小试牛刀

包建好了,下面就开始设计了,代码不着急。

首先,要知道我们要干什么,需要实现什么样的功能,用什么实现。

我们要访问网络,从网上加载数据,显示到街面上,使用mvp模式用一些开源库实现

好了,知道要干什么,知道了用什么方法实现,接下来就好弄了,很多时候,难就难在我们不晓得要干什么

获取数据,这么复杂的操作不能再activity中实现,本来人家和用户交互就够烦了,还把这么麻烦的事都交给他去做,后面可能会出事,咋们交给model去做,但是交给model做了,怎么把获取到的数据交给view了,这就需要我们设计好接口,通过回调的方式将数据返回给persenter,在通过persenter传递给View,实现了model层和view尽可能的解耦

Model

先定义两个IModle 的接口

package modle.Impl;

import java.util.List;

import bean.Book;

/**
 * Created by Administrator on 2017/9/7.
 */

public interface IBookModle extends IModle{
    void getBook(AsyncCallback callback,String name,int start,int count);
}
           
package modle.Impl;

/**
 * Created by limeng on 2017/9/7.
 */

public interface IModle {
     public interface AsyncCallback {

        void onSuccess(Object success);

        void onError(Object error);
    }
}
           

既然是获取数据,就需要有个获取数据的方法,通过getBook方法来获取数据,AsyncCallback 这个参数是等下回调的时候会传递过来的的参数,name书本的名字,start是从那条数据开始,count是获取多少条数据

package modle;

import android.util.Log;

import com.google.gson.Gson;


import bean.Book;
import impl.ApiService;
import modle.Impl.IBookModle;
import retrofit2.Retrofit;
import retrofit2.adapter.rxjava.RxJavaCallAdapterFactory;
import retrofit2.converter.gson.GsonConverterFactory;
import rx.android.schedulers.AndroidSchedulers;
import rx.functions.Action1;
import rx.schedulers.Schedulers;

/**
 * Created by limeng on 2017/9/7.
 */

public class BookModle implements IBookModle {
    private Retrofit mRetrofit;
    private ApiService request;
    @Override
    public void getBook(final AsyncCallback callback, String name, int start, int count) {
        mRetrofit = new Retrofit.Builder()
                .baseUrl("https://api.douban.com/v2/") // 设置
                .addConverterFactory(GsonConverterFactory.create(new Gson())) // 设置使用Gson解析(记得加入依赖)
                .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
                .build();
        // 步骤5:创建 网络请求接口 的实例
        request = mRetrofit.create(ApiService.class);
        // 对 发送请求 进行封装
        request.getCall(name, null, start, count)
                .subscribeOn(Schedulers.newThread())
                .doOnNext(new Action1<Book>() {
                    @Override
                    public void call(Book bean) {
                        Log.e("limeng", "doOnNext" + Thread.currentThread().getName());
                    }
                })
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Action1<Book>() {
                    @Override
                    public void call(Book book) {
                        callback.onSuccess(book);
                    }

                }, new Action1<Throwable>() {
                    @Override
                    public void call(Throwable throwable) {
                        callback.onError(throwable);
                    }
                });
    }
}
           

定义一个modelBook类实现IModelBook,重写他的getBook方法,然后获取数据,当请求成功时,通过persenter传递过来的callback回调callback.onSuccess(book);这样persenter就获取到了数据,请求失败时callback.onError(throwable);

persenter

同样是先定义接口

package presenter;

/**
 * Created by Administrator on 2017/9/6.
 */

public interface IBookPresenter {
    void loadBook(String name,int start,int count);
}
           

这个用来加载数据,其实方法名应该跟model换下的,model才是加载数据,persenter才是get数据

package presenter.Impl;

import android.content.Context;
import android.util.Log;
import android.widget.Toast;

import java.util.List;

import bean.Book;
import modle.BookModle;
import modle.Impl.IBookModle;
import modle.Impl.IModle;
import presenter.IBookPresenter;
import view.IBookView;

/**
 * Created by limeng on 2017/9/6.
 */

public class BookPresenter implements IBookPresenter{
    private IBookModle modle;
    private IBookView mBookView;
    public BookPresenter(IBookView view){
        mBookView=view;
        modle=new BookModle();
    }
    @Override
    public void loadBook(String name,int start,int count) {
        modle.getBook(new IModle.AsyncCallback() {
            @Override
            public void onSuccess(Object success) {
                Book book= (Book) success;
                mBookView.upDataBookList(book);
            }
            @Override
            public void onError(Object error) {
                Throwable throwable= (Throwable) error;
                Log.e("limeng","throwable="+throwable.toString());
                Toast.makeText((Context) mBookView,"加载数据失败",Toast.LENGTH_LONG).show();
            }
        },name,start,count);
    }
}
           

创建一个BookPresenter类实现接口,重写loadBook方法,弄一个构造函授,用来接收view,创建一个model的实例,再在loadBook方法中调用model的getBook方法,new一个AsyncCallback对象,重写他的

onSuccess(),            
onError()方法,这样就获取到了返回的数据,同时还要传递书名name,start,count,这三个参数就是你想要获取到什么样的数据

           

View

没得说,先定义接口

           
package view;

import java.util.List;

import bean.Book;

/**
 * Created by Administrator on 2017/9/7.
 */

public interface IBookView {
    void upDataBookList(Book book);
}
           
定义一个IBookView的接口,里面的upDataBookList主要是通过获取到的数据更新界面的
package com.limeng.ke.myapplication;

import android.app.Activity;
import android.os.Bundle;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.View;
import android.widget.Button;

import com.scwang.smartrefresh.layout.SmartRefreshLayout;
import com.scwang.smartrefresh.layout.api.RefreshLayout;
import com.scwang.smartrefresh.layout.listener.OnLoadmoreListener;
import com.scwang.smartrefresh.layout.listener.OnRefreshListener;

import java.util.List;

import adapter.RecyAdapter;
import bean.Book;
import fragment.MyFragment;
import presenter.IBookPresenter;
import presenter.Impl.BookPresenter;
import view.IBookView;


public class MainActivity extends Activity implements View.OnClickListener, MyFragment.LogLinsenter, IBookView {
    private Button btnLoadData;//点击加载数据
    private Button btnDelete;//删除数据
    private Button btnAdd;//添加数据

    private RefreshLayout mRefreshLayout;
    private RecyclerView mRecyclerView;
    private SmartRefreshLayout smartRefreshLayout;
    private RecyAdapter mAdapter = null;

    private Book book = null;
    private IBookPresenter mPresenter;
    private List<Book.BooksBean> mBoosBeanList;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
//      initData();
        initView();
        mPresenter = new BookPresenter(MainActivity.this);
        initData();
        initAdapter();
    }

    private void initData() {

    }

    private void initAdapter() {

    }

    private void initView() {
//        mRefreshLayout = (RefreshLayout) findViewById(R.id.refreshLayout);
        mRecyclerView = (RecyclerView) findViewById(R.id.recyclerview);
        mRefreshLayout = (RefreshLayout) findViewById(R.id.smartRefreshLayout);
        btnLoadData = (Button) findViewById(R.id.iv_Pic1);
        btnDelete = (Button) findViewById(R.id.btn_delete);
        btnAdd = (Button) findViewById(R.id.btn_add);
        btnLoadData.setOnClickListener(this);
        btnDelete.setOnClickListener(this);
        btnAdd.setOnClickListener(this);
//        Glide.with(MainActivity.this).load(Images.imageUrls[0]).into(ivPic1);
        mRefreshLayout.setOnRefreshListener(new OnRefreshListener() {
            @Override
            public void onRefresh(RefreshLayout refreshlayout) {
                int start = book.getStart();
                int count = book.getCount();
                //向下拉刷新
                Log.e("limeng", "正在刷新--------->start=" + start);
                Log.e("limeng", "正在刷新--------->count=" + count);
                refreshlayout.finishRefresh(5000);
            }

        });
        mRefreshLayout.setOnLoadmoreListener(new OnLoadmoreListener() {
            @Override
            public void onLoadmore(RefreshLayout refreshlayout) {
                //向上拉加載更多
                refreshlayout.finishLoadmore(5000);
            }
        });
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.iv_Pic1:
                mPresenter.loadBook("金瓶梅", 0, 10);
                break;
            case R.id.btn_add:
                mAdapter.addData(1);
                break;
            case R.id.btn_delete:
                mAdapter.removeData(1);
                break;
        }
    }

    @Override
    public void log(String name) {
    }

    @Override
    public void upDataBookList(Book book) {
        Log.e("limeng", "upDataBookList");
        this.book=book;
        mBoosBeanList = book.getBooks();
        RecyAdapter adapter = new RecyAdapter(MainActivity.this, mBoosBeanList);
        mRecyclerView.setLayoutManager(new LinearLayoutManager(this));//这里用线性显示 类似于listview
        mRecyclerView.setAdapter(adapter);
    }
}
           
activity实现IBookView接口,重写unDataBookList方法,实例化一个presenter对象,用户通过点击事件,想要获取数据,点击按钮,通过presenter对象调用 mPresenter.loadBook("金瓶梅", 0, 10);这个方法,然后会触发presenter中的model实例调用getBook方法,然后在触发model中的getBook方法获取数据,通过 AsyncCallback这个接口中的onSuccess(),onError()两个方法将数据回调给presenter,在presenter中通过IBookview接口中的 mBookView.upDataBookList(book);方法将数据回调给activity,最后activity重写upDataBookList(book)方法获取数据 最终实现了view发送指令,通过presenter交给model,model处理完逻辑,将数据通过presenter返回给activity,逻辑数据层与View的完美解耦,这样是代码更清晰,阅读起来更加容易,也利于代码的后期维护
最后附上demo代码http://download.csdn.net/download/u010471406/9970769