Retrofit应用小记

本文出自 “阿敏其人” 简书博客,转载或引用请注明出处。

一、为什么用Retrofit

1、因为Okhttp很牛逼
2、因为RxJava很热

因为Retrofit封装了okhttp,又因为RxJava和Retrofit的关系就像下雨天和巧克力。所以,折腾Retrofit。
RxJava参考链接

二、Retrofit初步应用

build.gradle引入相关库

    compile 'com.squareup.retrofit2:retrofit:2.1.0'
    compile 'com.squareup.retrofit2:converter-gson:2.1.0'
    compile 'com.squareup.retrofit2:adapter-rxjava:2.1.0'
    compile 'com.google.code.gson:gson:2.7'

开始最简单的demo

我们要请求网络数据了,那么来一个接口,get请求天气数据。

http://apistore.baidu.com/microservice/weather?citypinyin=beijing

典型的的Json返回类型:

{
  code:0,
  msg:"success"
  data:{...}
}

实际返回:

{
    "errNum": 0,
    "errMsg": "success",
    "retData": {
        "city": "接口已经停用",
        "pinyin": "apistore.baidu.com",
        "citycode": "000000000",
        "date": "201616-05-12",
        "time": "10:00",
        "postCode": "0000000",
        "longitude": 0,
        "latitude": 0,
        "altitude": "0",
        "weather": "多云",
        "temp": "0",
        "l_tmp": "0",
        "h_tmp": "0",
        "WD": "北风",
        "WS": "接口已经停用,请访问APIStore.baidu.com查找对应接口",
        "sunrise": "00:00",
        "sunset": "00:00"
    }
}

(虽显停用,无碍使用)

弄一个实体Bean吧,为了方便起见,public修饰

public class WeatherBean {
    public int errNum;
    public String errMsg;
    public RetDataBean retData;

    public static class RetDataBean {
        public String city;
        public String pinyin;
        public String citycode;
        public String date;
        public String time;
        public String postCode;
        public int longitude;
        public int latitude;
        public String altitude;
        public String weather;
        public String temp;
        public String l_tmp;
        public String h_tmp;
        public String WD;
        public String WS;
        public String sunrise;
        public String sunset;
    }
}

权限勿忘

    <uses-permission android:name="android.permission.INTERNET"/>

准备工作完毕

来来来,解析解析:

准备一个WeatherApi 接口

public interface WeatherApi {
    // 发送get请求,光是这段地址肯定不完整,待会我们还在在别的地方补上 baseurl 。 这里直接把后面的请求给写死了(这样肯定不好)
    @GET("/microservice/weather?citypinyin=beijing")
    Call<WeatherBean> getWeather();
}

MainActivity代码

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        getData();
    }

    private void getData() {
        String baseUrl = "http://apistore.baidu.com/";
        // 创建一个  retrofit ,baseUrl必须有
        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl(baseUrl)
                .addConverterFactory(GsonConverterFactory.create()) // 用到了 com.squareup.retrofit2:adapter-rxjava:2.1.0'
                .build();
        // 利用 retrofit 创建一个接口
        WeatherApi apiService = retrofit.create(WeatherApi.class);

        // 利用接口创建一个Call对象
        Call<WeatherBean> weatherBeanCall = apiService.getWeather();
        // 请求入队,回调请求成功或者失败
        weatherBeanCall.enqueue(new Callback<WeatherBean>() {
            @Override
            public void onResponse(Call<WeatherBean> call, Response<WeatherBean> response) {
                System.out.println("====请求成功:"+response.body().retData.weather);
            }
            @Override
            public void onFailure(Call<WeatherBean> call, Throwable t) {
                System.out.println("====请求失败");
            }
        });
    }
}

.
.
运行打印结果:

 ====请求成功:多云

第一次就这么跑下来了。

代码分析

(数据和bean的就不说了,只从Retroift说起)

  • 第一步、准备一个接口,比如名为WeatherApi,接口里面通过注解的方式说明请求方式,比如这里我们指定为GET。
public interface WeatherApi {
    // 发送get请求,光是这段地址肯定不完整,待会我们还在在别的地方补上 baseurl 。 这里直接把后面的请求给写死了(这样肯定不好)
    @GET("/microservice/weather?citypinyin=beijing")
    Call<WeatherBean> getWeather();
}

(GET当然可以传参,我们这里先通过一个不规范的行为写死了,后面会补充会有更好的方式)

  • 第二步,创建一个retrofit 对象,传入对象baseUrl,指定数据将解析为何种对象。
    .baseUrl(baseUrl),好理解
    .addConverterFactory(GsonConverterFactory.create()) 将数据解析成Gson对象
    .build就成功创建 retrofit 对象了

  • 第三步,利用retrofit对象得到一个接口实例。

  • 第四步,利用接口实例得到Call对象,让Call对象异步入队。入队支队就会有两个回调方法 ,成功还是失败。

大概流程就是这么走的。

get传参

我们改一下代码

在WeatherApi里面,利用@Query可以传参

public interface APIService {
    // 发送get请求,光是这段地址肯定不完整,待会我们还在在别的地方补上 baseurl 。 这里直接把后面的请求给写死了(这样肯定不好)
    // 请求还是Get
    @GET("/microservice/weather")
    Call<WeatherBean> getWeather(@Query("citypinyin") String city); // 使用了@Query,后面的 citypinyin 是参数名
}

get方式的url里面,问号不用写,@Query("citypinyin")是key,String city是值类型和参数名。

MainActivity也需要修改下

    private void getData() {
        String baseUrl = "http://apistore.baidu.com/";
        // 创建一个  retrofit ,baseUrl必须有
        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl(baseUrl)
                .addConverterFactory(GsonConverterFactory.create()) // 用到了 com.squareup.retrofit2:adapter-rxjava:2.1.0'
                .build();
        // 利用 retrofit 创建一个接口
        WeatherApi apiService = retrofit.create(WeatherApi.class);

        // 利用接口创建一个Call对象
        Call<WeatherBean> weatherBeanCall = apiService.getWeather("beijing");
        // 请求入队,回调请求成功或者失败
        weatherBeanCall.enqueue(new Callback<WeatherBean>() {
            @Override
            public void onResponse(Call<WeatherBean> call, Response<WeatherBean> response) {
                System.out.println("====请求成功:"+response.body().retData.weather);
            }
            @Override
            public void onFailure(Call<WeatherBean> call, Throwable t) {
                System.out.println("====请求失败");
            }
        });
    }

改动的只有一行代码

 Call<WeatherBean> weatherBeanCall = apiService.getWeather("beijing");

打印结果一致。

除了@Query传参,还由@Path等,请求方式里面有Get,Post等也是支持的,这里就不演示了。

二、Retrofit + RxJava

引入多两个库

    compile 'com.android.support:appcompat-v7:23.4.0'
    compile 'com.squareup.retrofit2:retrofit:2.1.0'
    compile 'com.squareup.retrofit2:converter-gson:2.1.0'
    compile 'com.squareup.retrofit2:adapter-rxjava:2.1.0'
    compile 'com.google.code.gson:gson:2.7'

    compile 'io.reactivex:rxjava:1.1.6'
    compile 'io.reactivex:rxandroid:1.2.1'

简单结合

既然引入RxJava,那么就应该是 观察者 和 被观察者。

我们先看看在原有的代码里面观察者和被观察者的角色分别是谁在扮演

Paste_Image.png

被观察者

在上面的代码中,我们的 apiService 扮演者 被观察者 的角色,所以在接口里面的返回值我们就不可以用Call,而应该用 Observable

public interface WeatherApi {
    @GET("/microservice/weather")
    Observable<WeatherBean> getWeather(@Query("citypinyin") String city);
}

观察者

在上面的分析图里面,new Callback<WeatherBean> 扮演的是 观察者 的角色,所以要做一个调整

如下

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        getData();
    }
    private void getData() {
        String baseUrl = "http://apistore.baidu.com/";
        // 创建一个  retrofit ,baseUrl必须有
        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl(baseUrl)
                .addConverterFactory(GsonConverterFactory.create())
                .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) // //添加 RxJava 适配器
                .build();
        // 利用 retrofit 创建一个接口
        WeatherApi apiService = retrofit.create(WeatherApi.class);

        // 被观察者
        Observable observable = apiService.getWeather("beijing")
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread());

        // 观察者
        Subscriber<WeatherBean> subscriber = new Subscriber<WeatherBean>() {
            @Override
            public void onCompleted() {
            }

            @Override
            public void onError(Throwable e) {
                System.out.println("====请求失败");
            }

            @Override
            public void onNext(WeatherBean weatherBean) {
                System.out.println("====请求成功:" + weatherBean.retData.weather);
            }
        };
        // 产生订阅关系
        observable.subscribe(subscriber);
    }
}

在上面 观察者 和 被观察者 只要熟悉RxJava的可以理解。

** RxJavaCallAdapterFactory **

但是需要注意的是,retrofit 的配置里面要加多一句 .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) // //添加 RxJava 适配器
这个很重要

       Retrofit retrofit = new Retrofit.Builder()
                .baseUrl(baseUrl)
                .addConverterFactory(GsonConverterFactory.create())
                .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) // //添加 RxJava 适配器
                .build();

CallAdapter.Factory 是 Retrofit 这个库中的接口,用来给我们自定义去解析我们自己想要的类型用的。

举个栗子:

@GET("/aaa")Observable<QuestionListData> getQuestionNewestList();

比如这么一个接口, retrofit本身是无法识别 Observable<QuestionListData>然后去工作的,如果没有这个适配器就根本无法工作,因此我们的适配器的作用,就是生成我们想要的 Observable 。

三、封装请求

在上面的代码中,每次请求都需要new 一个Retrofit实例,这样肯定是不好的。
所以我们弄一个单例,把请求封装起来。

借鉴 RxJava 与 Retrofit 结合的最佳实践

封装代码:

public class HttpMethods {

    public static final String BASE_URL = "http://apistore.baidu.com/";

    private static final int DEFAULT_TIMEOUT = 5;

    private Retrofit retrofit;
    private WeatherApi weatherApi;

    //构造方法私有
    private HttpMethods() {
        //手动创建一个OkHttpClient并设置超时时间
        OkHttpClient.Builder httpClientBuilder = new OkHttpClient.Builder();
        httpClientBuilder.connectTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS);

        retrofit = new Retrofit.Builder()
                .client(httpClientBuilder.build())
                .addConverterFactory(GsonConverterFactory.create())
                .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
                .baseUrl(BASE_URL)
                .build();

        weatherApi = retrofit.create(WeatherApi.class);
    }

    //在访问HttpMethods时创建单例
    private static class SingletonHolder{
        private static final HttpMethods INSTANCE = new HttpMethods();
    }

    //获取单例
    public static HttpMethods getInstance(){
        return SingletonHolder.INSTANCE;
    }

    public void getWeather(Subscriber<WeatherBean> subscriber, String city){
        weatherApi.getWeather(city)
                .subscribeOn(Schedulers.io())
                .unsubscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(subscriber);
    }
}

接下来ManActivity自己要这么做就好

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        getData();
    }
    private void getData() {
        // 观察者
        Subscriber<WeatherBean> subscriber = new Subscriber<WeatherBean>() {
            @Override
            public void onCompleted() {
            }

            @Override
            public void onError(Throwable e) {
                System.out.println("====请求失败");
            }

            @Override
            public void onNext(WeatherBean weatherBean) {
                System.out.println("====请求成功:" + weatherBean.retData.weather);
            }
        };
        // 产生订阅关系
        HttpMethods.getInstance().getWeather(subscriber,"beijing");
    }
}

几乎一行代码完成。

四、服务器返回数据统一处理

比如服务器返回的数据是统一是如下格式:
{
code:0,
msg:"success"
data:{...}
}

code和msg是固定格式int和String,data不固定,可能是数组,可能是一个对象。
那么这个data就是泛型T

然后在Activity和Fragment里面我不关心code和msg,我们只关心data。
对于code我们可以做一个预处理,如果预处理code不等于0,那么就直接执行onError了。

我们把WeatherBean删掉,实体Bean我们可以拆分成这样

Paste_Image.png

这么做之后,自然很多报错,那么来解决。

第一处修改

Observable参数类型换成 GeneralResults<RetDataBean>


Paste_Image.png
public interface WeatherApi {
    @GET("/microservice/weather")
    Observable<GeneralResults<RetDataBean>> getWeather(@Query("citypinyin") String city);
}

第二处

Paste_Image.png

public class HttpMethods {

    public static final String BASE_URL = "http://apistore.baidu.com/";

    private static final int DEFAULT_TIMEOUT = 5;

    private Retrofit retrofit;
    private WeatherApi weatherApi;

    //构造方法私有
    private HttpMethods() {
        //手动创建一个OkHttpClient并设置超时时间
        OkHttpClient.Builder httpClientBuilder = new OkHttpClient.Builder();
        httpClientBuilder.connectTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS);

        retrofit = new Retrofit.Builder()
                .client(httpClientBuilder.build())
                .addConverterFactory(GsonConverterFactory.create())
                .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
                .baseUrl(BASE_URL)
                .build();

        weatherApi = retrofit.create(WeatherApi.class);
    }

    //在访问HttpMethods时创建单例
    private static class SingletonHolder{
        private static final HttpMethods INSTANCE = new HttpMethods();
    }

    //获取单例
    public static HttpMethods getInstance(){
        return SingletonHolder.INSTANCE;
    }

    public void getWeather(Subscriber<GeneralResults<RetDataBean>> subscriber, String city){
        weatherApi.getWeather(city)
                .subscribeOn(Schedulers.io())
                .unsubscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(subscriber);
    }
}

第三处:

Paste_Image.png
public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        getData();
    }
    private void getData() {
        // 观察者
        Subscriber<GeneralResults<RetDataBean>> subscriber = new Subscriber<GeneralResults<RetDataBean>>() {
            @Override
            public void onCompleted() {
            }

            @Override
            public void onError(Throwable e) {
                System.out.println("====请求失败");
            }

            @Override
            public void onNext(GeneralResults<RetDataBean> weatherBean) {
                System.out.println("====请求成功:" + weatherBean.retData.weather);
            }
        };
        // 产生订阅关系
        HttpMethods.getInstance().getWeather(subscriber,"beijing");
    }
}

依然结果不变,你可以说,这不就是把相关的5个原先的WeatherBean换成GeneralResults<RetDataBean>吗,是的没错,有这个认识挺好的。

我们先来想一下,这5个地方的类型需要完全一致吗?
对于 被观察者 来说,也就是WeatherApi里面的返回值Observable,这里的参数类型需要跟返回的Json数据对应,这样才靠谱
对于 观察者 Subscriber来说,他的类型是不需要跟着Observable一样的,但是直接写不一样的类型肯定不可以,但是我们可以通过map变换等把 被观察者 传入的数据类型 转换成 观察者 想要的其他类型。

我们知道,被观察者需要的是 GeneralResults<RetDataBean> ,但是观察者需要的是 RetDataBean 而已。

也就是说,我们可以把 被观察者 传入的GeneralResults<RetDataBean> 变换成 观察者 想要的 RetDataBean。

根据上面的代码,我们接着来。

利用变换统一处理返回的数据类型。

被观察者需要的是 GeneralResults<RetDataBean> ,但是观察者需要的是 RetDataBean 而已。

这里我们用map进行变换
GeneralResults<RetDataBean>变RetDataBean 是一个一对一的操作。
如果data是一个数组或者集合,那么我们可以用flatMap,平铺变换,这个支持一对多。

Paste_Image.png

上代码:
WeatherApi

public interface WeatherApi {
    @GET("/microservice/weather")
    Observable<GeneralResults<RetDataBean>> getWeather(@Query("citypinyin") String city);
}

上图中,HttpMethods 采用的是map变换,下面的实际代码中我们为了演示多一种用法,我们采用flatMap
(虽然在当前情况下不需要flatMap,但是flatMap依然可以良好地完成工作)

HttpMethods

public class HttpMethods {

    public static final String BASE_URL = "http://apistore.baidu.com/";

    private static final int DEFAULT_TIMEOUT = 5;

    private Retrofit retrofit;
    private WeatherApi weatherApi;

    //构造方法私有
    private HttpMethods() {
        //手动创建一个OkHttpClient并设置超时时间
        OkHttpClient.Builder httpClientBuilder = new OkHttpClient.Builder();
        httpClientBuilder.connectTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS);

        retrofit = new Retrofit.Builder()
                .client(httpClientBuilder.build())
                .addConverterFactory(GsonConverterFactory.create())
                .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
                .baseUrl(BASE_URL)
                .build();

        weatherApi = retrofit.create(WeatherApi.class);
    }

    //在访问HttpMethods时创建单例
    private static class SingletonHolder{
        private static final HttpMethods INSTANCE = new HttpMethods();
    }

    //获取单例
    public static HttpMethods getInstance(){
        return SingletonHolder.INSTANCE;
    }

    public void getWeather(Subscriber<RetDataBean> subscriber, String city){
        weatherApi.getWeather(city)
            .flatMap(new Func1<GeneralResults<RetDataBean>, Observable<RetDataBean>>() {
                @Override
                public Observable<RetDataBean> call(GeneralResults<RetDataBean> retDataBeanGeneralResults) {
                    return flatResult(retDataBeanGeneralResults);
                }
            })
            .subscribeOn(Schedulers.io())
            .unsubscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(subscriber);
    }

    static <T> Observable<T> flatResult(final GeneralResults<T> result) {
        return Observable.create(new Observable.OnSubscribe<T>() {
            @Override
            public void call(Subscriber<? super T> subscriber) {
                if (result.errNum!= 0) {
                    subscriber.onError(new ApiException(ApiException.USER_NOT_EXIST));
                } else{
                    subscriber.onNext(result.retData);
                }
                subscriber.onCompleted();
            }
        });
    }
}

MainActivity

public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        getData();
    }
    private void getData() {
        // 观察者
        Subscriber<RetDataBean> subscriber = new Subscriber<RetDataBean>() {
            @Override
            public void onCompleted() {
            }

            @Override
            public void onError(Throwable e) {
                System.out.println("====请求失败");
            }

            @Override
            public void onNext(RetDataBean weatherBean) {
                System.out.println("====请求成功:" + weatherBean.weather);
            }
        };
        // 产生订阅关系
        HttpMethods.getInstance().getWeather(subscriber,"beijing");
    }
}

WeatherApi

public interface WeatherApi {
    @GET("/microservice/weather")
    Observable<GeneralResults<RetDataBean>> getWeather(@Query("citypinyin") String city);
}

ApiException

public class ApiException extends RuntimeException {

    public static final int USER_NOT_EXIST = 100;
    public static final int WRONG_PASSWORD = 101;

    public ApiException(int resultCode) {
        this(getApiExceptionMessage(resultCode));
    }

    public ApiException(String detailMessage) {
        super(detailMessage);
    }

    /**
     * 由于服务器传递过来的错误信息直接给用户看的话,用户未必能够理解
     * 需要根据错误码对错误信息进行一个转换,在显示给用户
     * @param code
     * @return
     */
    private static String getApiExceptionMessage(int code){
        String message = "";
        switch (code) {
            case USER_NOT_EXIST:
                message = "该用户不存在";
                break;
            case WRONG_PASSWORD:
                message = "密码错误";
                break;
            default:
                message = "未知错误";

        }
        return message;
    }
}

运行效果一致。

五、如何去掉调用

如果没有使用Rxjava,那么Service返回的是一个Call,而这个Call对象有一个cancel方法可以用来取消Http请求。那么用了Rxjava之后,如何来取消一个请求呢

我们在Activity或者Fragment中创建subscriber对象,想要取消请求的时候调用subscriber的unsubscribe方法就可以了。

六、加载时的Dialog

Paste_Image.png

加载时,dilalog弹出
完成、错误时dialog消失

dialog跟订阅关系同步

ProgressCancelListener

public interface ProgressCancelListener {
    void onCancelProgress();
}

.
.
ProgressDialogHandler

public class ProgressDialogHandler extends Handler {

    public static final int SHOW_PROGRESS_DIALOG = 1;
    public static final int DISMISS_PROGRESS_DIALOG = 2;

    private ProgressDialog pd;

    private Context context;
    private boolean cancelable;
    private ProgressCancelListener mProgressCancelListener;

    public ProgressDialogHandler(Context context, ProgressCancelListener mProgressCancelListener,
                                 boolean cancelable) {
        super();
        this.context = context;
        this.mProgressCancelListener = mProgressCancelListener;
        this.cancelable = cancelable;
    }

    private void initProgressDialog(){
        if (pd == null) {
            pd = new ProgressDialog(context);

            pd.setCancelable(cancelable);

            if (cancelable) {
                pd.setOnCancelListener(new DialogInterface.OnCancelListener() {
                    @Override
                    public void onCancel(DialogInterface dialogInterface) {
                        mProgressCancelListener.onCancelProgress();
                    }
                });
            }

            if (!pd.isShowing()) {
                pd.show();
            }
        }
    }

    private void dismissProgressDialog(){
        if (pd != null) {
            pd.dismiss();
            pd = null;
        }
    }

    @Override
    public void handleMessage(Message msg) {
        switch (msg.what) {
            case SHOW_PROGRESS_DIALOG:
                initProgressDialog();
                break;
            case DISMISS_PROGRESS_DIALOG:
                dismissProgressDialog();
                break;
        }
    }

}

.
.

SubscriberOnNextListener

public interface SubscriberOnNextListener<T> {
    void onNext(T t);
}

.
.
ProgressSubscriber

public class ProgressSubscriber<T> extends Subscriber<T> implements ProgressCancelListener {

    private SubscriberOnNextListener mSubscriberOnNextListener;
    private ProgressDialogHandler mProgressDialogHandler;

    private Context context;


    public ProgressSubscriber(SubscriberOnNextListener mSubscriberOnNextListener, Context context) {
        this.mSubscriberOnNextListener = mSubscriberOnNextListener;
        this.context = context;
        mProgressDialogHandler = new ProgressDialogHandler(context, this, true);
    }

    private void showProgressDialog() {
        if (mProgressDialogHandler != null) {
            mProgressDialogHandler.obtainMessage(ProgressDialogHandler.SHOW_PROGRESS_DIALOG).sendToTarget();
        }
    }

    private void dismissProgressDialog() {
        if (mProgressDialogHandler != null) {
            mProgressDialogHandler.obtainMessage(ProgressDialogHandler.DISMISS_PROGRESS_DIALOG).sendToTarget();
            mProgressDialogHandler = null;
        }
    }

    @Override
    public void onStart() {
        showProgressDialog();
    }

    @Override
    public void onCompleted() {
        dismissProgressDialog();
        Toast.makeText(context, "Get Top Movie Completed", Toast.LENGTH_SHORT).show();
    }

    @Override
    public void onError(Throwable e) {
        dismissProgressDialog();
        Toast.makeText(context, "error:" + e.getMessage(), Toast.LENGTH_SHORT).show();
    }

    @Override
    public void onNext(T t) {
        mSubscriberOnNextListener.onNext(t);
    }

    @Override
    public void onCancelProgress() {
        if (!this.isUnsubscribed()) {
            this.unsubscribe();
        }
    }
}

最后,MainActivity

public class MainActivity extends AppCompatActivity {

    private TextView mTvGet;
    private TextView mTvResult;

    private SubscriberOnNextListener getWeatherNext;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mTvGet = (TextView) findViewById(R.id.mTvGet);
        mTvResult = (TextView) findViewById(R.id.mTvResult);
        mTvGet.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                HttpMethods.getInstance().getWeather(new ProgressSubscriber(getWeatherNext, MainActivity.this), "beijing");
            }
        });

        getWeatherNext = new SubscriberOnNextListener<RetDataBean>() {
            @Override
            public void onNext(RetDataBean retDataBean) {
                mTvResult.setText("==========:"+retDataBean.weather);
            }
        };

    }

}

有点困,几个接口不分析了。

本篇完。

参考学习:

RxJava 与 Retrofit 结合的最佳实践

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,029评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,395评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,570评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,535评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,650评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,850评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,006评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,747评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,207评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,536评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,683评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,342评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,964评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,772评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,004评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,401评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,566评论 2 349

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,799评论 25 707
  • 我从去年开始使用 RxJava ,到现在一年多了。今年加入了 Flipboard 后,看到 Flipboard 的...
    Jason_andy阅读 5,460评论 7 62
  • 前言我从去年开始使用 RxJava ,到现在一年多了。今年加入了 Flipboard 后,看到 Flipboard...
    占导zqq阅读 9,159评论 6 151
  • 场景无数遍在脑海里划过,那只是幻觉幻想,不算数的。清醒的眼神,麻木的悲凉,还略带些苍桑和墨白。穿过高楼小区,这种梦...
    Milly_e33a阅读 129评论 0 1
  • 如水的思念 寄挂明月 踩着月影 瘦成一亩良田 夜色里桂花弥香 选择了自由 就不怕月光的清冷 选择了遗忘 就不怕风的...
    ec406fac4d1a阅读 510评论 0 0