Android MVP +Retrofit+RxJava

来源:互联网 发布:mac npm安装webpack 编辑:程序博客网 时间:2024/04/30 20:23

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

MVP

再简单说一下,M:model 数据逻辑和实体模型 V:view 指Activity负责页面显示与交互 P:presenter model与view的接口持有者,减少了Model与View的联系,降低了耦合度。

Model

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;        }    }}

View

由于Presenter持有的是View的接口所以View的接口也就必不可少

View接口

/** * 只作为一个标记 */public interface IView {}

具体的weatherview

public interface WeatherView extends  IView{//两个方法进行回调,onsuccess的方法参数根据需要设置    void onSuccess(WeatherModel model);    void onError(String res);}

Presenter

由于不确定之后的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<T> {    public String errno;    public String msg;    public T data;}

Model接口具体思路参考http://blog.csdn.net/lyhhj/article/details/51720296

Retrofit2.0

下面一讲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<WeatherModel> call = apiStores.getWeather("101010100");        call.enqueue(new Callback<WeatherModel>() {            @Override            public void onResponse(Call<WeatherModel> call, Response<WeatherModel> response) {                mView.onSuccess(response.body());            }            @Override            public void onFailure(Call<WeatherModel> 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<WeatherModel> 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<WeatherModel> getWeather(@Query("q") String a);

@QueryMap(get请求)
传递参数比较多时

 @GET("adat/sk") Call<WeatherModel> 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<USer> setUserInfo(@Field("username") String username ,@Field("password") String password);

@Header

 @POST("adat/sk") Call<WeatherModel> getWeather(@Header("Authorization") String Authorization);

@Headers

  @Headers("Cache-Control: max-age=640000")  @GET("/tasks")  Call<List<Task>> getTasks();


3、异步请求,获取返回值

WeatherApi apiStores = retrofit.create(WeatherApi.class);//异步请求,获取返回值Call<WeatherModel> call = apiStores.getWeather("101010100");        call.enqueue(new Callback<WeatherModel>() {            @Override            public void onResponse(Call<WeatherModel> call, Response<WeatherModel> response) {                mView.onSuccess(response.body());            }            @Override            public void onFailure(Call<WeatherModel> call, Throwable t) {            }        });

RxJava

先来看看Rxjava与MVP跟Retrofit结合是怎么使用的,再来介绍Rxjava 的使用及Scheduler 线程控制。
1、要先修改WeatherApi,将返回值类型Call修改为Observable。

public interface WeatherApi{    @GET("adat/sk/{cityId}.html")    Observable<WeatherModel> 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<WeatherModel> observable = apiStores.getWeather("101010100");        observable.subscribeOn(Schedulers.io())        //请求数据事件发生在io线程中                .observeOn(AndroidSchedulers.mainThread())                //请求完成后再主线程更新UI                .subscribe(new Observer<WeatherModel>() {                    @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 2.0

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<String> observable= Observable.create(new ObservableOnSubscribe<String>() {            @Override            public void subscribe(ObservableEmitter<String> e) throws Exception {            //此时被观察者发生变化                e.onNext("a");                e.onNext("b");                e.onComplete();            }        });

//观察者

Observer<String> observer=new Observer<String>() {            @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<String>() {            @Override            public void subscribe(ObservableEmitter<String> e) throws Exception {                e.onNext("a");                e.onNext("b");                e.onComplete();            }        }).subscribe(new Observer<String>() {            @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

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<Integer> obs=Observable.just(1,2,3,4);       //在调用 subscribe方法之前先设置线程控制器及具体的线程       obs.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(new Observer<Integer>() {            @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

0 0