您的位置:首页 > 编程语言 > Java开发

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

2017-04-25 13:29 429 查看
前言:之前就学习了相关的知识,一直未结合使用,现在打算结合起来使用,这个例子就是包含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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  mvp rxjava retrofit2-0
相关文章推荐