MVP +Retrofit+RxJava这三个结合使用好像已经火了一段时间了,有时候我们只是学会了使用,却不能深刻理解。之前写过两篇关于mvp的使用跟理解的文章。感兴趣的可以看一下,这篇文章关于mvp就不多解释了。这里只说最简单的MVP +Retrofit+RxJava三者结合使用的demo,因为说多了一方面不容易消化一方面容易乱,一步一步的消化之后才能深入理解,而且具体的一些变化还要根据项目尽心修改。
http://blog.csdn.net/danfengw/article/details/51829746
http://blog.csdn.net/danfengw/article/details/51902665
再简单说一下,M:model 数据逻辑和实体模型 V:view 指Activity负责页面显示与交互 P:presenter model与view的接口持有者,减少了Model与View的联系,降低了耦合度。
demo请求地址 http://www.weather.com.cn/adat/sk/101010100.html
请求数据:
{"weatherinfo":{"city":"北京","cityid":"101010100","temp":"10","WD":"东南风","WS":"2级","SD":"26%","WSE":"2","time":"10:25","isRadar":"1","Radar":"JC_RADAR_AZ9010_JB","njd":"暂无实况","qy":"1012"}}
model生成有种简单的方法:
直接用AndroidStudio的GsonFormat插件就可以生成File——setting——Browser reponsitorise
安装一下,重启AS,创建一个类比如下面的WeatherModel 类,然后alt+insert快捷键选择GosonFormat然后将上面的json串复制进去,就可以自动生成了,大概如下所示。需要注意的是,此时
你生成的类中可能并没有Weatherinfo 这个内部类,可能是其他的类名,如果不是Weatherinfo 则需要自己手动修改为Weatherinfo 这个类名,如果不注意这一点,后面你可能就掉坑里怎么都出不来了,这是什么原因呢?这是由于后面我们要结合retrofit进行网络请求。
public class WeatherModel {
/**
* weatherinfo : {"city":"北京","cityid":"101010100","temp":"10","WD":"东南风","WS":"2级","SD":"26%","WSE":"2","time":"10:25","isRadar":"1","Radar":"JC_RADAR_AZ9010_JB","njd":"暂无实况","qy":"1012"}
*/
private Weatherinfo weatherinfo;
public Weatherinfo getWeatherinfo() {
return weatherinfo;
}
public void setWeatherinfo(Weatherinfo weatherinfo) {
this.weatherinfo = weatherinfo;
}
public static class Weatherinfo {
/**
* city : 北京
* cityid : 101010100
* temp : 10
* WD : 东南风
* WS : 2级
* SD : 26%
* WSE : 2
* time : 10:25
* isRadar : 1
* Radar : JC_RADAR_AZ9010_JB
* njd : 暂无实况
* qy : 1012
*/
private String city;
private String cityid;
private String temp;
private String WD;
private String WS;
private String SD;
private String WSE;
private String time;
private String isRadar;
private String Radar;
private String njd;
private String qy;
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
public String getCityid() {
return cityid;
}
public void setCityid(String cityid) {
this.cityid = cityid;
}
public String getTemp() {
return temp;
}
public void setTemp(String temp) {
this.temp = temp;
}
public String getWD() {
return WD;
}
public void setWD(String WD) {
this.WD = WD;
}
public String getWS() {
return WS;
}
public void setWS(String WS) {
this.WS = WS;
}
public String getSD() {
return SD;
}
public void setSD(String SD) {
this.SD = SD;
}
public String getWSE() {
return WSE;
}
public void setWSE(String WSE) {
this.WSE = WSE;
}
public String getTime() {
return time;
}
public void setTime(String time) {
this.time = time;
}
public String getIsRadar() {
return isRadar;
}
public void setIsRadar(String isRadar) {
this.isRadar = isRadar;
}
public String getRadar() {
return Radar;
}
public void setRadar(String Radar) {
this.Radar = Radar;
}
public String getNjd() {
return njd;
}
public void setNjd(String njd) {
this.njd = njd;
}
public String getQy() {
return qy;
}
public void setQy(String qy) {
this.qy = qy;
}
}
}
由于Presenter持有的是View的接口所以View的接口也就必不可少
/**
* 只作为一个标记
*/
public interface IView {
}
具体的weatherview
public interface WeatherView extends IView{
//两个方法进行回调,onsuccess的方法参数根据需要设置
void onSuccess(WeatherModel model);
void onError(String res);
}
由于不确定之后的View究竟是哪个View因此在Presenter中使用泛型。
public class IPresenter<T extends IView> {
T mView;
//将view绑定防止内存泄露
public void onCreate(T view) {
mView = view;
}
public void onDestroy() {
if (mView != null) {
mView = null;
}
}
}
具体的presenter
public class WeatherPresenter extends IPresenter<WeatherView> {
public void getView(){
//这里进行网络请求获取数据,获取到数据调用weatherview的onsuccess方法
}
}
public class DemoActivity extends AppCompatActivity implements WeatherView {
TextView mTv;
WeatherPresenter mPresenter;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.demo_activity);
mTv = (TextView) findViewById(R.id.tv);
mPresenter=new WeatherPresenter();
mPresenter.onCreate(this);
mPresenter.getView();
}
@Override
public void onSuccess(WeatherModel model) {
WeatherModel weatherInfo =model;
String str = "" + weatherInfo.getWeatherinfo().getCity() + weatherInfo.getWeatherinfo().getWD();
mTv.setText(str);
}
@Override
public void onError(String res) {
}
}
小结:
1、Model:学习GsonFormat插件,注意类名一致性
2、View:IView标识类
3、Presenter:持有Model和View接口,上面的model并没有给出接口,我们可以设置Model接口。因为平时我们的请求信息一般都是这种带有 “errno”“msg”和”data”:的
{
"errno": "no",
"msg": "成功",
"data": {
"weatherinfo": {
"city": "北京",
"cityid": "101010100",
"temp": "10",
"WD": "东南风",
"WS": "2级",
"SD": "26%",
"WSE": "2",
"time": "10:25",
"isRadar": "1",
"Radar": "JC_RADAR_AZ9010_JB",
"njd": "暂无实况",
"qy": "1012"
}
}
}
此时可以将给Model写个接口
public class IModel {
public String errno;
public String msg;
public T data;
}
Model接口具体思路参考http://blog.csdn.net/lyhhj/article/details/51720296
下面一讲retrofit可能就要跑远了,为了mvp跟retrofit的完整理解就先把retrofit请求部分代码放在这里,后面会有详细介绍。
public class WeatherPresenter extends IPresenter<WeatherView> {
public void getView() {
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("http://www.weather.com.cn/")
.addConverterFactory(GsonConverterFactory.create())
.build();
// http://www.weather.com.cn/adat/sk/101010100.html
WeatherApi apiStores = retrofit.create(WeatherApi.class);
Call call = apiStores.getWeather("101010100");
call.enqueue(new Callback() {
@Override
public void onResponse(Call call, Response response) {
mView.onSuccess(response.body());
}
@Override
public void onFailure(Call call, Throwable t) {
}
});
}
}
看到这里可以先将mvp+retrofit仔细捋一遍逻辑了。
官网配置
使用
1、Retrofit 网址配置
retrofit的基础配置只配置前半部分http://www.weather.com.cn/后面部分由于带有请求参数,在具体的请求api中进行设置
// http://www.weather.com.cn/adat/sk/101010100.html
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("http://www.weather.com.cn/")
.addConverterFactory(GsonConverterFactory.create())
.build();
2、api
进行URL拼接
public interface WeatherApi{
@GET("adat/sk/{cityId}.html")
Call getWeather(@Path("cityId") String cityId);
}
api请求参数类有2个注意点:
(1)注解请求方式get
retrofit的请求方式当然不会只有get一种方式,具体根据需要使用,比如:
GET-——查找资源
POST——修改资源
PUT——上传文件
DELETE——删除文件
HEAD——之请求页面首部
(2)参数拼接@Path,retrofit除了@Path注解外还有其他的比如:@Query@QueryMap @Body @FormUrlEncoded @Field @Header @Headers
@Query(get请求)
假设请求url为http://www.weather.com.cn/adat/sk?q=a
@GET("adat/sk")
Call getWeather(@Query("q") String a) ;
@QueryMap(get请求)
传递参数比较多时
@GET("adat/sk")
Call getWeather(@QueryMap Map<String,String> a);
@Body(post请求)
假设存在Weather 类,指定一个对象作为Http请求体
@POST("adat/sk")
Call<WeatherModel> getWeather(@Body Weather weather);
@Field(post请求)
用于传递表单数据
@POST("user/info")
Call setUserInfo(@Field("username") String username ,@Field("password") String password) ;
@Header
@POST("adat/sk")
Call getWeather(@Header("Authorization") String Authorization) ;
@Headers
@Headers("Cache-Control: max-age=640000")
@GET("/tasks")
Call> getTasks();
3、异步请求,获取返回值
WeatherApi apiStores = retrofit.create(WeatherApi.class);
//异步请求,获取返回值
Call call = apiStores.getWeather("101010100");
call.enqueue(new Callback() {
@Override
public void onResponse(Call call, Response response) {
mView.onSuccess(response.body());
}
@Override
public void onFailure(Call call, Throwable t) {
}
});
先来看看Rxjava与MVP跟Retrofit结合是怎么使用的,再来介绍Rxjava 的使用及Scheduler 线程控制。
1、要先修改WeatherApi,将返回值类型Call修改为Observable。
public interface WeatherApi{
@GET("adat/sk/{cityId}.html")
Observable getWeather(@Path("cityId") String cityId);
}
2、通过subscribeon对io线程事件订阅监听
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("http://www.weather.com.cn/")
.addConverterFactory(GsonConverterFactory.create())
.build();
// http://www.weather.com.cn/adat/sk/101010100.html
WeatherApi apiStores = retrofit.create(WeatherApi.class);
Observable observable = apiStores.getWeather("101010100");
observable.subscribeOn(Schedulers.io())
//请求数据事件发生在io线程中
.observeOn(AndroidSchedulers.mainThread())
//请求完成后再主线程更新UI
.subscribe(new Observer() {
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onNext(WeatherModel model) {
//请求成功进行回调
mView.onSuccess(model);
}
@Override
public void onError(Throwable e) {
//请求发生错误
}
@Override
public void onComplete() {
//所有事件完成,进行相关操作
}
});
Rxjava基本思想是一个观察者模式,所以对Rxjava的理解就少不了观察者(Observer)和被观察者(Observable),此外还有一个subscribe订阅需要理解。
观察者模式:所有的观察者观察一个被观察者,在被观察者发生某些变化时,所有观察者会做出以下反应。
Observable:在观察者模式中称为“被观察者”;
Observer:观察者模式中的“观察者”,可接收Observable发送的数据;
//下面这两个可以暂且不看
subscribe:订阅,观察者与被观察者,通过subscribe()方法进行订阅;
Subscriber:也是一种观察者,在2.0中 它与Observer没什么实质的区别,不同的是 Subscriber要与Flowable(也是一种被观察者)联合使用,该部分内容是2.0新增的,后续文章再介绍。Obsesrver用于订阅Observable,而Subscriber用于订阅Flowable
rxjava中定义了onext()、onCompleted()、onError()几个方法。
//被观察者
Observable observable= Observable.create(new ObservableOnSubscribe() {
@Override
public void subscribe(ObservableEmitter e) throws Exception {
//此时被观察者发生变化
e.onNext("a");
e.onNext("b");
e.onComplete();
}
});
//观察者
Observer observer=new Observer() {
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onNext(String s) {
//对变化做出反应
System.out.print(s);
}
@Override
public void onError(Throwable e) {
}
@Override
public void onComplete() {
}
};
订阅
observable.subscribe(observer);
或者直接这样写
Observable.create(new ObservableOnSubscribe() {
@Override
public void subscribe(ObservableEmitter e) throws Exception {
e.onNext("a");
e.onNext("b");
e.onComplete();
}
}).subscribe(new Observer() {
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onNext(String s) {
System.out.print(s);
}
@Override
public void onError(Throwable e) {
}
@Override
public void onComplete() {
}
})
Observable的创建还有其他的方式比如just from等
http://reactivex.io/documentation/operators.html
比如:
Observable<String> observable = Observable.just("Hello", "Hi", "Aloha");
//传递集合的
List<String> list = new ArrayList<String>();
for(int i =0;i<10;i++){
list.add("Hello"+i);
}
Observable observable = Observable.fromIterable(list);
//设置时间间隔,每隔2秒调用一次onNext()方法
Observable<String> observable = Observable.interval(2, TimeUnit.SECONDS);
Scheduler 是个调度器,主要用于对线程的控制,Rxjava1.x就已经有自带的几个Scheduler 的相关线程了。
Schedulers.immediate(): 直接在当前线程运行,相当于不指定线程。这是默认的 Scheduler。
Schedulers.newThread(): 总是启用新线程,并在新线程执行操作。
Schedulers.io(): I/O 操作(读写文件、读写数据库、网络信息交互等)所使用的 Scheduler。行为模式和 newThread() 差不多,区别在于 io() 的内部实现是是用一个无数量上限的线程池,可以重用空闲的线程,因此多数情况下 io() 比 newThread() 更有效率。不要把计算工作放在 io() 中,可以避免创建不必要的线程。
Schedulers.computation(): 计算所使用的 Scheduler。这个计算指的是 CPU 密集型计算,即不会被 I/O 等操作限制性能的操作,例如图形的计算。这个 Scheduler 使用的固定的线程池,大小为 CPU 核数。不要把 I/O 操作放在 computation() 中,否则 I/O 操作的等待时间会浪费 CPU。
另外, Android 还有一个专用的 AndroidSchedulers.mainThread(),它指定的操作将在 Android 主线程运行。
Observable obs=Observable.just(1,2,3,4);
//在调用 subscribe方法之前先设置线程控制器及具体的线程
obs.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(new Observer() {
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onNext(Integer integer) {
}
@Override
public void onError(Throwable e) {
}
@Override
public void onComplete() {
}
});
http://gank.io/post/560e15be2dca930e00da1083