1. 程式人生 > >例項帶你瞭解Retrofit 2.0的使用,分享目前開發Retrofit遇到的坑和心得

例項帶你瞭解Retrofit 2.0的使用,分享目前開發Retrofit遇到的坑和心得

新增依賴

app/build.gradle

1
compile 'com.squareup.retrofit2:retrofit:2.0.0-beta3'

介面呼叫

1
2
3
4
5
6
Retrofit retrofit = new Retrofit.Builder()
                //這裡建議:- Base URL: 總是以/結尾;- @Url: 不要以/開頭
               .baseUrl("http://www.weather.com.cn/")
               .build();
       ApiStores apiStores = retrofit.create(ApiStores.class);
Call<ResponseBody> call = apiStores.getWeather("101010100");
1
<uses-permission android:name="android.permission.INTERNET" />

同步呼叫

1
2
3
4
5
6
7
try {
          Response<ResponseBody> bodyResponse = call.execute();
          String body = bodyResponse.body().string();//獲取返回體的字串
Log.i("wxl", "body=" + body); } catch (IOException e) { e.printStackTrace(); }

同步需要處理android.os.NetworkOnMainThreadException

非同步呼叫

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
call.enqueue(new Callback<ResponseBody>() {
            @Override
            public void
onResponse(Response<ResponseBody> response)
{
try { Log.i("wxl", "response=" + response.body().string()); } catch (IOException e) { e.printStackTrace(); } } @Override public void onFailure(Throwable t) { Log.i("wxl", "onFailure=" + t.getMessage()); } });

移除請求

1
call.cancel();

介面引數

Path

1
2
3
4
5
6
7
8
9
 /**
 * Call<T> get();必須是這種形式,這是2.0之後的新形式
 * 如果不需要轉換成Json資料,可以用了ResponseBody;
 * 你也可以使用Call<GsonBean> get();這樣的話,需要新增Gson轉換器
 */
public interface ApiStores {
    @GET("adat/sk/{cityId}.html")
    Call<ResponseBody> getWeather(@Path("cityId") String cityId);
}

Query

1
2
@GET("http://ip.taobao.com/service/getIpInfo.php")
   Call<ResponseBody> getWeather(@Query("ip") String ip);

Body

這是針對POST方式,如果引數是json格式,如:

1
2
3
4
5
6
{		
    "apiInfo": {		
        "apiName": "WuXiaolong",		
        "apiKey": "666"		
}		
}

建立Bean

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class ApiInfo {
       private ApiInfoBean apiInfo;

       public ApiInfoBean getApiInfo() {
           return apiInfo;
       }

       public void setApiInfo(ApiInfoBean apiInfo) {
           this.apiInfo = apiInfo;
       }

       public class ApiInfoBean {
           private String apiName;
           private String apiKey;
           //省略get和set方法
       }
   }

程式碼呼叫

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
private void getCarType() {
       mRetrofit = new Retrofit.Builder()
               .baseUrl("http://WuXiaolong.me/")
               .addConverterFactory(GsonConverterFactory.create())
               .build();
       ApiStores apiStores = mRetrofit.create(ApiStores.class);
       ApiInfo apiInfo = new ApiInfo();
       ApiInfo.ApiInfoBean apiInfoBean = apiInfo.new ApiInfoBean();
       apiInfoBean.setApiKey("666");
       apiInfoBean.setApiName("WuXiaolong");
       apiInfo.setApiInfo(apiInfoBean);
       Call<ResponseBody> call = apiStores.getCarType(apiInfo);
       call.enqueue(new Callback<ResponseBody>() {
           @Override
           public void onResponse(Response<ResponseBody> response) {
               String body = null;//獲取返回體的字串
               try {
                   body = response.body().string();
               } catch (IOException e) {
                   e.printStackTrace();
               }
               Log.i("wxl", "get=" + body);
           }

           @Override
           public void onFailure( Throwable t) {

           }

       });
   }

ApiStores

1
2
3
4
public interface ApiStores {
        @POST("client/shipper/getCarType")
        Call<ResponseBody> getCarType(@Body ApiInfo apiInfo);
    }

JSON解析庫

Retrofit 2現在支援許多種解析方式來解析響應資料,包括Moshi,一個由Square建立的高效JSON解析庫。

新增gson依賴

app/build.gradle

1
compile 'com.squareup.retrofit2:converter-gson:2.0.0-beta3'

jsonschema2pojo

訪問jsonschema2pojo,自動生成Java物件,如果你對gson還不熟悉,筆者建議你手動生成Java物件,感受下。

這裡如果選擇Gson,生成的程式碼中存在@Generated註解,Android預設並沒有javax.annotation library。如果你希望保留@Generated註解,需要新增如下的依賴。

1
compile 'org.glassfish:javax.annotation:10.0-b28'

或者,你可以直接刪除這個註解,完全沒有問題。筆者當然不會加這個依賴啦。

Gsonformat

作用:Android studio外掛,一般介面返回資料後要建立自己的bean,Gsonformat幫助你快速生成,不用一條一條去寫。比jsonschema2pojo更加簡單。
安裝步驟:Android studio-Settings-Plugins-搜Gsonformat-Install Plugin
效果預覽:

例項程式碼

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public class WeatherJson {
    //weatherinfo需要對應json資料的名稱,我之前隨便寫了個,被坑很久
    private Weatherinfo weatherinfo;

    public Weatherinfo getWeatherinfo() {
        return weatherinfo;
    }

    public void setWeatherinfo(Weatherinfo weatherinfo) {
        this.weatherinfo = weatherinfo;
    }
    //city、cityid必須對應json資料的名稱,不然解析不了
    public class Weatherinfo {
        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;
        //這裡省略get和set方法
    }
}

ApiStores:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class AppClient {
    static Retrofit mRetrofit;

    public static Retrofit retrofit() {
        if (mRetrofit == null) {
            mRetrofit = new Retrofit.Builder()
                    .baseUrl("http://www.weather.com.cn/")
                    .addConverterFactory(GsonConverterFactory.create())
                    .build();
        }
        return mRetrofit;
    }

    public interface ApiStores {
        @GET("adat/sk/{cityId}.html")
        Call<WeatherJson> getWeather(@Path("cityId") String cityId);
    }
}

呼叫:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
private void getWeather() {
       AppClient.ApiStores apiStores = AppClient.retrofit().create(AppClient.ApiStores.class);
       Call<WeatherJson> call = apiStores.getWeather("101010100");
       call.enqueue(new Callback<WeatherJson>() {
           @Override
           public void onResponse(Response<WeatherJson> response) {
               Log.i("wxl", "getWeatherinfo=" + response.body().getWeatherinfo().getCity());
           }

           @Override
           public void onFailure(Throwable t) {

           }
       });
   }

經Gson轉換器,Call<ResponseBody>換成自己要寫的Call<WeatherJson>

RxJava

依賴以下:

1
2
compile 'com.squareup.retrofit:adapter-rxjava:2.0.0-beta3'
compile 'io.reactivex:rxandroid:1.0.1'

增加addCallAdapterFactory

1
2
3
4
5
Retrofit retrofit = new Retrofit.Builder()
        .baseUrl("http://api.nuuneoi.com/base/")
        .addConverterFactory(GsonConverterFactory.create())
        .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
        .build();

ApiStores

1
2
@GET("adat/sk/{cityId}.html")
Observable<WeatherJson> getWeatherRxjava(@Path("cityId") String cityId);

subscribe部分的程式碼在Schedulers.io被呼叫,需要把observeOn(AndroidSchedulers.mainThread())新增到連結串列中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
private void getWeatherRxjava() {
       AppClient.ApiStores apiStores = AppClient.retrofit().create(AppClient.ApiStores.class);
       Observable<WeatherJson> observable = apiStores.getWeatherRxjava("101010100");
       observable.subscribeOn(Schedulers.io())
               .observeOn(AndroidSchedulers.mainThread())
               .subscribe(new Observer<WeatherJson>() {
                   @Override
                   public void onCompleted() {
                       Log.i("wxl", "onCompleted");
                   }

                   @Override
                   public void onError(Throwable e) {
                       Log.i("wxl", "e=" + e.getMessage());
                   }

                   @Override
                   public void onNext(WeatherJson weatherJson) {
                       Log.i("wxl", "getWeatherinfo=" + weatherJson.getWeatherinfo().getCity());
                   }
               });

   }