一个例子包含mvp、rxjava以及retrofit2的使用

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/zhujiangtaotaise/article/details/70738314

前言:之前就学习了相关的知识,一直未结合使用,现在打算结合起来使用,这个例子就是包含mvp、rxjava以及retrofit2的基本用法。下一篇文章会基于这篇文章的基础介绍dagger2的用法。

首先,在gralde文件中引入后续要用到的库:

//rxjava 以及rxandroid
 compile 'io.reactivex:rxjava:1.0.14'
 compile 'io.reactivex:rxandroid:1.0.1'
 //retrofit
 compile 'com.squareup.retrofit2:retrofit:2.0.2'
 compile 'com.squareup.retrofit2:converter-gson:2.0.2'
 //okhttp 以及在retrofit中使用rxjava要导入的库
 compile 'com.squareup.okhttp3:okhttp:3.1.2'
 compile 'com.squareup.retrofit2:adapter-rxjava:2.0.2'
 //图片加载经典库universalimageloader
 compile 'com.nostra13.universalimageloader:universal-image-loader:1.9.5'

MVP这里就简单介绍下:
View :负责绘制UI元素、与用户进行交互(在Android中体现为Activity);

View interface :需要View实现的接口,View通过View interface与 Presenter进行交互,降低耦合,方便进行单元测试;

Model :负责存储、检索、操纵数据(有时也实现一个Model interface用来降低耦合)

Presenter :作为View与Model交互的中间纽带,处理与用户交互的负责逻辑。

注意 presenter和view的交互一般是通过接口来实现的。view和model是不能直接交互的,以上设计主要是为了降低代码间的耦合。

我们这里的例子是使用上面的这些框架来实现listview中数据的填充,数据来源于网络。使用retrofit 实现数据的下载和解析,rxjava来保持代码简洁以及线程间的快速切换。

项目的结构如下图:

这里写图片描述

MyServiceBase 代码如下:

public class MyServiceBase {
    public static IMyService getService(boolean isGetImg, int readTimeOut, int connectTimeOut){

        OkHttpClient client = new OkHttpClient.Builder()
                .readTimeout(readTimeOut <= 0 ? 30 : readTimeOut, TimeUnit.SECONDS)
                .connectTimeout(connectTimeOut <= 0 ? 30 : connectTimeOut, TimeUnit.SECONDS)
                .build();
        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl(isGetImg ? "http://img.mukewang.com/":"http://www.imooc.com/")
                .addConverterFactory(GsonConverterFactory.create())//gson 解析
                .addCallAdapterFactory(RxJavaCallAdapterFactory.create())// rxjava 方法
                .client(client)
                .build();

        IMyService myService = retrofit.create(IMyService.class);

        return myService;
    }
}

该类主要就是初始化retrofit,以及通过参数isGetImg来选择是加载图片还是加载数据,很简单,都有注释。

IMyService代码如下:

public interface IMyService {
    @GET("api/teacher")
    Observable<DataBean> getData(@Query("type") int type, @Query("num") int num);

    @GET
    Observable<ResponseBody> getBitmap(@Url String url);
}

getData 是获取数据,getBitmap是用于listview每个item获取图片。
@GET(“api/teacher”) 以及@Query(“type”)都是retrofit的基本用法,用来填充获取数据的URL。

MyImageLoaderUtils 是用来获取图片的,其中增加了用LruCache做图片缓存,代码如下:

public class MyImageLoaderUtils {

    private LruCache<String , Bitmap> bitmapLruCache ;

    private ImageView imageView;
    private String mImgUrl;

    public MyImageLoaderUtils(){
        int maxMemorySize = (int) Runtime.getRuntime().maxMemory();
        int cacheSize = maxMemorySize/4;

        bitmapLruCache = new LruCache<String , Bitmap>(cacheSize){
            @Override
            protected int sizeOf(String key, Bitmap value) {
                return value.getByteCount();
            }
        };
    }

    private void setBitmapToCache(String url, Bitmap bm){
        if(getBitmapFromCache(url) == null){
            bitmapLruCache.put(url, bm);
        }
    }

    private Bitmap getBitmapFromCache(String url){
        return bitmapLruCache.get(url);
    }

    public void setImgByUrl(ImageView imgView, String url) {
        mImgUrl = url;

        Bitmap bm = getBitmapFromCache(url);
        if(bm != null){
            imgView.setImageBitmap(bm);
        }else{
            getBitmap(imgView, url);
        }
    }

    public interface ImgService {
        @GET
        Observable<ResponseBody> getImgBody(@Url String url);
    }

    private void getBitmap(final ImageView imgView, final String url) {

        IMyService imgService = MyServiceBase.getService(true, 0, 0);

        imgService.getBitmap(url).subscribeOn(Schedulers.newThread())
                .observeOn(Schedulers.io())//io线程获取图片
                .map(new Func1<ResponseBody, Bitmap>() {//map方法是用来将ResponseBody转换成Bitmap输出
                    @Override
                    public Bitmap call(ResponseBody responseBody) {
                        InputStream is = null;

                        try {
                            is = responseBody.byteStream();
                        } catch (Exception e) {
                            e.printStackTrace();
                        } finally {
                            try {
                                if (is != null) {
                                    is.close();
                                }
                            } catch (IOException e) {
                                e.printStackTrace();
                            }
                        }
                        if (is != null) {
                            return BitmapFactory.decodeStream(is);
                        }
                        return null;
                    }
                }).observeOn(AndroidSchedulers.mainThread())//跳转到主线程
                .subscribe(new Action1<Bitmap>() {
                    @Override
                    public void call(Bitmap bitmap) {
                        Log.e(TestListViewActivity.TAG, "bitmap = " + bitmap);
                        bitmapLruCache.put(url, bitmap);
                        String imgUrl = (String) imgView.getTag();
                        if(imgUrl.equals(url)){//防止滑动listview的时候图片加载错乱
                            imgView.setImageBitmap(bitmap);
                        }
                    }
                });
    }
}

上面用到了rxjava的主要方法都有注释。

下面主要是mvp的内容了,我们的界面很简单,就是ListView和progressbar,当加载数据的时候显示progressbar,加载数据完成后 隐藏progressbar。

所以我们先定义一个IBaseView接口,Presenter就是通过该接口和View交互。
我们这个接口需要哪几个方法呢?
1. 请求数据是要显示 progressbar
2. 请求数据完成是要隐藏 progressbar
3. 请求数据成功后将数据set到View中。
4. 请求数据失败要toast “获取数据失败”

public interface IBaseView {
    void showProgressView();
    void hideProgressView();
    void setData(List<DataBean.ItemData> datas);
    void getDataFailed();
}

在MainActivity里面实现IBaseView 接口:

public class MainActivity extends Activity implements IBaseView {

    private ProgressBar mProgressBar;
    private ListView mListView;
    private List<DataBean.ItemData> mdDatas;
    private LvAdapter mLvAdapter;
    private MainPresenter mMainPresenter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.mvp_rxjava_dagger2_retrofit2_main_layout);

        initView();
        mMainPresenter.getLessonData();
    }

    private void initView() {
        mProgressBar = (ProgressBar) findViewById(R.id.mvp_rxjava_progressbar);
        mListView = (ListView) findViewById(R.id.mvp_rxjava_listview);
        mdDatas = new ArrayList<>();
        mLvAdapter = new LvAdapter(this);

        mMainPresenter = new MainPresenter(this);
    }

    @Override
    public void showProgressView() {
        mProgressBar.setVisibility(View.VISIBLE);
    }

    @Override
    public void hideProgressView() {
        mProgressBar.setVisibility(View.INVISIBLE);
    }

    @Override
    public void setData(List<DataBean.ItemData> datas) {
        mLvAdapter.setItemDataList(datas);
        mListView.setAdapter(mLvAdapter);
    }

    @Override
    public void getDataFailed() {

        Toast.makeText(this, "获取数据失败", Toast.LENGTH_SHORT).show();
    }
}

MainActivity 持有Presenter,通过Presenter来请求数据,MainPresenter如下:

public class MainPresenter  {

    private final static String TAG  = "MainPresenter";
    private MainModel mainModel;
    private IBaseView baseView;

    public MainPresenter(IBaseView baseView){
        this.baseView = baseView;
        mainModel = new MainModel();
    }

    public void getLessonData(){
        baseView.showProgressView();
        mainModel.getData(new onDataListener() {
            @Override
            public void onSuccess(List<DataBean.ItemData> datas) {
                Log.e(TAG, "onSuccess thread name = "+Thread.currentThread().getName());
                baseView.setData(datas);
                baseView.hideProgressView();
            }

            @Override
            public void onFailed() {
                Log.e(TAG, "onFailed thread name = "+Thread.currentThread().getName());
                baseView.getDataFailed();
                baseView.hideProgressView();
            }
        });
    }

   public interface onDataListener {
        void onSuccess(List<DataBean.ItemData> datas);
        void onFailed();
    }

MainPresenter 中持有 IBaseView,以及请求数据操作的Model。由于rxjava在请求数据完成后将现场转到主线程,所以我们可以在回调onSuccess以及onFailed 中操作UI。
MainModel 如下:

public class MainModel {

    private static final String TAG = "MainModel";

    public void getData(final MainPresenter.onDataListener listener) {

        IMyService myService = MyServiceBase.getService(false, 0, 0);

        myService.getData(4, 30).subscribeOn(Schedulers.newThread())//在子线程中下载
                .observeOn(AndroidSchedulers.mainThread())//数据下载好后转到main线程
                .subscribe(new Subscriber<DataBean>() {
            @Override
            public void onCompleted() {

            }

            @Override
            public void onError(Throwable e) {
                Log.e(TAG, e.getMessage());
                if (listener != null) {
                    listener.onFailed();
                }

            }

            @Override
            public void onNext(DataBean dataBean) {

                Log.e(TAG, "SIZE = " + dataBean.getDatas().size());
                List<DataBean.ItemData> datas = dataBean.getDatas();
                if (listener != null) {
                    listener.onSuccess(datas);
                }
            }
        });
    }

下一篇在本文的基础上讲 dagger2的应用。

学习rxjava
可以访问:https://gank.io/post/560e15be2dca930e00da1083

猜你喜欢

转载自blog.csdn.net/zhujiangtaotaise/article/details/70738314