1、爲何用Retrofit
一、由於Okhttp很牛逼二、由於RxJava很熱
由於Retrofit封裝了okhttp,又由於RxJava和Retrofit的關係就像下雨天和巧克力。因此,折騰Retrofit。RxJava參考連接
2、Retrofit初步應用
build.gradle引入相關庫java
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'react
開始最簡單的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;android
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 {git
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
getData();
}api
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 對象了app
第三步,利用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等也是支持的,這裏就不演示了。
2、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 。
3、封裝請求
在上面的代碼中,每次請求都須要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");
}
}
幾乎一行代碼完成。
4、服務器返回數據統一處理
好比服務器返回的數據是統一是以下格式:{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;
}
}
運行效果一致。
5、如何去掉調用
若是沒有使用Rxjava,那麼Service返回的是一個Call,而這個Call對象有一個cancel方法能夠用來取消Http請求。那麼用了Rxjava以後,如何來取消一個請求呢
咱們在Activity或者Fragment中建立subscriber對象,想要取消請求的時候調用subscriber的unsubscribe方法就能夠了。
6、加載時的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);
}
};
}
}
原文連接:http://www.jianshu.com/p/c1b2af70f24b
1、爲何用Retrofit
一、由於Okhttp很牛逼二、由於RxJava很熱
由於Retrofit封裝了okhttp,又由於RxJava和Retrofit的關係就像下雨天和巧克力。因此,折騰Retrofit。RxJava參考連接
2、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等也是支持的,這裏就不演示了。
2、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 。
3、封裝請求
在上面的代碼中,每次請求都須要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");
}
}
幾乎一行代碼完成。
4、服務器返回數據統一處理
好比服務器返回的數據是統一是以下格式:{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;
}
}
運行效果一致。
5、如何去掉調用
若是沒有使用Rxjava,那麼Service返回的是一個Call,而這個Call對象有一個cancel方法能夠用來取消Http請求。那麼用了Rxjava以後,如何來取消一個請求呢
咱們在Activity或者Fragment中建立subscriber對象,想要取消請求的時候調用subscriber的unsubscribe方法就能夠了。
6、加載時的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);
}
};
}
}
原文連接:http://www.jianshu.com/p/c1b2af70f24b
推薦查看: http://gank.io/post/56e80c2c677659311bed9841?hmsr=toutiao.io&utm_medium=toutiao.io&utm_source=toutiao.io