Android MVP +Retrofit+RxJava

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
Android MVP +Retrofit+RxJava_第1张图片
安装一下,重启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 {
    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 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仔细捋一遍逻辑了。
官网配置
Android MVP +Retrofit+RxJava_第2张图片

使用
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

先来看看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 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()几个方法。
Android MVP +Retrofit+RxJava_第3张图片

简单用法

//被观察者

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等
Android MVP +Retrofit+RxJava_第4张图片
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 的相关线程了。
Android MVP +Retrofit+RxJava_第5张图片

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

你可能感兴趣的:(Android)