这篇文章主要介绍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中写代码了,先得把架构打起来,然后再慢慢填充内容,就像建房子一样,一步一步来。先把包建好,这个自由发挥,没有固定的模式,看起来一目了然就行了,别后期找个类都要找半天,不晓得在哪个包里面,还得一个一个的看
包建好了,下面就开始设计了,代码不着急。
首先,要知道我们要干什么,需要实现什么样的功能,用什么实现。
我们要访问网络,从网上加载数据,显示到街面上,使用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