1. 程式人生 > >Retrofit 最簡單的快速入門及封裝

Retrofit 最簡單的快速入門及封裝

  • Retrofit是Square公司開發的一款針對Android網路請求的框架,Retrofit2底層基於OkHttp實現的,OkHttp現在已經得到Google官方認可,大量的app都採用OkHttp做網路請求
  • Retrofit也就成了最火的網路請求框架之一,想著來研究一下Retrofit了…先看了看官方文件,發現各種坑,Retrofit是結合著註解來做的,思路新穎,但是不符合大部分開發程式設計師的思維習慣,一開始使用的時候,不太適應…附上官方文件的介紹
Retrofit turns your HTTP API into a Java interface.

public interface GitHubService {
  @GET
("users/{user}/repos") Call<List<Repo>> listRepos(@Path("user") String user); } The Retrofit class generates an implementation of the GitHubService interface. Retrofit retrofit = new Retrofit.Builder() .baseUrl("https://api.github.com/") .build(); GitHubService service = retrofit.create(GitHubService.class
); Each Call from the created GitHubService can make a synchronous or asynchronous HTTP request to the remote webserver. Call<List<Repo>> repos = service.listRepos("octocat");
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

快速入門,從Hello 百度走起

  • 想快速入門Retrofit,我們最簡單的想法是能請求一下www.baidu.com,然後將資訊列印一下,但是發現在Retrofit入門的時候,訪問www.baidu.com竟然成了奢求…,大部分的文章都是模仿著官方文件來寫的…
  • 先一起來寫一個訪問百度,展示資料的示例
  • 第一步:gradle檔案中進行配置
 compile 'com.squareup.retrofit2:retrofit:2.0.0-beta2'
 compile 'com.squareup.retrofit2:adapter-rxjava:2.0.0-beta2'
 compile 'com.squareup.retrofit2:converter-scalars:2.0.0'
  • 1
  • 2
  • 3
  • 第二步:定義一個介面,介面中使用註解註明請求方式,及對應的請求路徑
public interface DataService {
    //指定get請求方式  指定路徑 有時候路徑除了baseUrl還有一部分比如 http://write.blog.csdn.net/mdeditor  
    //http://write.blog.csdn.net/ 一般是baseUrl
    //而 mdeditor是相對路徑的
    @GET
    Call<String> baidu(@Url String url);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 第二步:進行請求

      //建立Retrofit物件
        Retrofit retrofit = new Retrofit.Builder()
       //指定baseurl,這裡有坑,最後字尾出帶著“/” 
                .baseUrl("http://www.baidu.com/")
       //設定內容格式,這種對應的資料返回值是String型別
            .addConverterFactory(ScalarsConverterFactory.create())
       //定義client型別
                .client(new OkHttpClient())
       //建立
                .build();
        //通過retrofit和定義的有網路訪問方法的介面關聯
        DataService dataService = retrofit.create(DataService.class);
        //在這裡又重新設定了一下baidu的地址,是因為Retrofit要求傳入具體,如果是決定路徑的話,路徑會將baseUrl覆蓋掉
        Call<String> baidu = dataService.baidu("http://wwww.baidu.com");
        //執行非同步請求
        baidu.enqueue(new Callback<String>() {
            @Override
            public void onResponse(Call<String> call, Response<String> response) {
                Toast.makeText(MainActivity.this,  response.body(), Toast.LENGTH_SHORT).show();
            }
            @Override
            public void onFailure(Call<String> call, Throwable t) {

            }
        });
  • 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
  • 通過上述程式碼,咱們就可以完整的看見百度的html介面了,算是對Retrofit做一個入門

其他請求-QQ吉凶測試

{"error_code":0,"reason":"success","result":{"data":{"conclusion":"[大吉+官運+財運+才藝]如龍得雲,青雲直上,智謀奮進,才略奏功","analysis":"慾望難足希望高,計謀成功財力豪,猜疑嫉妒性自改,如龍乘雲勢運開。智慧超人貫徹大志,富貴無比,不甘寂寞,叱吒風雲之大吉數,但容易發生牢騷及貪心、慾望太多而永不知足,為其缺點。切忌沉迷投機,可免貽誤前程。"}}}
  • 1

對於Retrofit可以直接生成對應的json

  • 第一步:生成對應的Bean,例如 QQData

  • 第二步:在介面中定義請求方法

    • GET請求
    • 請求相對路徑
    • 引數內容
    • Call代表是一個請求
public interface DataService {
    @GET("/qqevaluate/qq")
    Call<QQData> getQQData(@Query("key") String appkey, @Query("qq") String qq);
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 第三步:開始請求
 Retrofit retrofit = new Retrofit.Builder()
                .baseUrl("http://japi.juhe.cn")
                .addConverterFactory(GsonConverterFactory.create()).build();
        DataService dataService = retrofit.create(DataService.class);

        final Call<QQData> qqData = dataService.getQQData("96efc220a4196fafdfade0c9d1e897ac", "11111111");
        qqData.enqueue(new Callback<QQData>() {
            @Override
            public void onResponse(Response<QQData> response, Retrofit retrofit) {

                String reason = response.body().getReason();

                Toast.makeText(MainActivity.this, response.body().getReason(), Toast.LENGTH_SHORT).show();
            }

            @Override
            public void onFailure(Throwable t) {
                Toast.makeText(MainActivity.this, "--" + t.getMessage().toString(), Toast.LENGTH_SHORT).show();
            }
        });
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 以上是Retrofit的簡單應用,當然對於Retrofit還有一些其他的方式
 ///https://zhidao.baidu.com/daily/view
    //路徑拼接的形式,v代表是其中的一個引數,可以在這個位置進行拼接
    @GET("daily/{v}")
    Call<String> baiduzhidao(@Path("v") String v);
 //在註解中指定路徑,定義相對應的引數的集合
  @GET("qqevaluate/qq")
    Call<QQData> getQQDataMap(@QueryMap Map<String,String> map);
    //對應Post請求,引數的註解是@Field
    @POST("qqevaluate/qq")
    Call<QQData>  postQQData(@Field("key") String key,@Field("qq") String qq);

    //必須指定進行表單編碼
    @FormUrlEncoded
    //指定引數是map形式 @FieldMap
    @POST("qqevaluate/qq")
    Call<QQData> postQQDataMap(@FieldMap Map<String,String> map);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

自己封裝一個簡易的Retrofit請求

  • 對於Retrofit,我們發現確實有一些特色,請求也比較簡單,但是,當在一個大的專案中,不可能每一請求都到介面中宣告一下。所以有必要進行簡易的封裝

  • 封裝一個簡易的請求介面


public interface ProjectAPI {
    //http://www.baidu.com/aaa?key=123&qq=aaa

    @GET
    Call<String> getMethod(@Url String url);

    @FormUrlEncoded
    @POST
    Call<String> postMethod(@Url String url, @FieldMap Map<String,String> map);

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 定義一個網路請求的管理類,需要注意的是這裡的baseUrl建立了,如果url是在其基礎上的,就會進行相應的拼接,如果url是全路徑,就會覆蓋掉baseUrl
public class HttpManger {
 /**
     * @param baseUrl  基礎Url
     * @param url       附加Url
     * @param callback  新增請求回撥,這裡直接使用的是Retrofit自身的回撥介面
     */
    public static void getMethod(String baseUrl, String url, final Callback<String> callback) {
        Retrofit retrofit = new Retrofit.Builder().baseUrl(baseUrl).addConverterFactory(ScalarsConverterFactory.create()).build();

        ProjectAPI projectAPI = retrofit.create(ProjectAPI.class);

        Call<String> call = projectAPI.getMethod(url);
        call.enqueue(new Callback<String>() {
            @Override
            public void onResponse(Call<String> call, Response<String> response) {
            //呼叫回撥
                callback.onResponse(call, response);
            }

            @Override
            public void onFailure(Call<String> call, Throwable t) {
               //呼叫回撥
                callback.onFailure(call, t);
            }
        });
    }
  • 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
  • Post請求方式的封裝,引數通過map集合的方式進行傳遞
  public static void postMethod(String baseUrl, String url, Map<String, String> map, final Callback<String> callback) {


        //指定客戶端
        Retrofit retrofit = new Retrofit.Builder().baseUrl(baseUrl).client(httpClient).addConverterFactory(ScalarsConverterFactory.create()).build();

        ProjectAPI projectAPI = retrofit.create(ProjectAPI.class);

        Call<String> call = projectAPI.postMethod(url, map);

        call.enqueue(new Callback<String>() {
            @Override
            public void onResponse(Call<String> call, Response<String> response) {
                callback.onResponse(call, response);
            }
            @Override
            public void onFailure(Call<String> call, Throwable t) {
                callback.onFailure(call, t);
            }
        });
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 方法呼叫-Get方式呼叫,這裡的key大家可以替換一下
 HttpManger.getMethod("http://japi.juhe.cn/", "http://japi.juhe.cn/qqevaluate/qq?key=96efc220a4196fafdfade0c9d1e897ac&qq=295424589", new Callback<String>() {
            @Override
            public void onResponse(Call<String> call, Response<String> response) {
                Toast.makeText(MainActivity.this, "--"+response.body(), Toast.LENGTH_SHORT).show();
            }

            @Override
            public void onFailure(Call<String> call, Throwable t) {
                Toast.makeText(MainActivity.this, "--"+t.getMessage(), Toast.LENGTH_SHORT).show();
            }
        });
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • POST方式呼叫
Map<String, String> map=new HashMap<>();
        map.put("key","96efc220a4196fafdfade0c9d1e897ac");
        map.put("qq","111111111");
        HttpManger.postMethod(false,false,"http://japi.juhe.cn/","qqevaluate/qq",map,new Callback<String>(){
            @Override
            public void onResponse(Call<String> call, Response<String> response) {
                Toast.makeText(MainActivity.this, "--"+response.body(), Toast.LENGTH_SHORT).show();
            }

            @Override
            public void onFailure(Call<String> call, Throwable t) {
                Toast.makeText(MainActivity.this, "--"+t.getMessage(), Toast.LENGTH_SHORT).show();
            }
        });
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 正好最近做到了Cookie的應用,在本講解中進行一下講解
  • 建立一個儲存Cookie的攔截器,用於獲取伺服器打給客戶端的Cookie資訊
public class SaveCookiesInterceptor implements Interceptor {
    @Override
    public okhttp3.Response intercept(Chain chain) throws IOException {
        //獲取到響應
        Response originalResponse = chain.proceed(chain.request());
        //進行Cookie獲取以及字串的拼接,Cookie在使用的過程要
        //根據具體公司來定

        if (!originalResponse.headers("Set-Cookie").isEmpty()) {
            //根據Set-Cookie獲取出的資訊
            for (String header : originalResponse.headers("Set-Cookie")) {
                Log.i("AAAA----","=="+header+"==");
                String cookie = header.substring(0, header.indexOf(";") + 1);
                stringBuilder.append(cookie);
            }
        }
      //拼接時完成後將該Cookie儲存到 SharedPreferences中
      SharedPreferencesUtils.saveString(MyApplication.context,"cookie",stringBuilder.toString());
        return originalResponse;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 建立讀取Cookie的攔截器
public class ReadCookiesInterceptor implements Interceptor {

    @Override
    public okhttp3.Response intercept(Chain chain) throws IOException {
        Request.Builder builder = chain.request().newBuilder();
        String cookie = SharedPreferencesUtils.getString(MyApplication.context, "cookie", "");
        //將cookie新增到請求頭中
        builder.addHeader("Cookie", cookie);
        return chain.proceed(builder.build());
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 在HttpManager中指定攔截器的使用,但是並不是所有的請求都要儲存cookie或者所有的請求都要讀取cookie,所以我們新增一個判斷
 /**
     * 
     * @param isReadCookie  是否要讀取cookie
     * @param isSaveCookie  是否要儲存cookie
     * @param baseUrl        基礎Url
     * @param url            要拼接的url   
     * @param map            引數集合
     * @param callback       請求回撥
     */
    public static void postMethod(boolean isReadCookie, boolean isSaveCookie, String baseUrl, String url, Map<String, String> map, final Callback<String> callback) {

        OkHttpClient httpClient = null;
        if (isReadCookie && !isSaveCookie) {
            httpClient = new OkHttpClient.Builder()
                    .addInterceptor(new ReadCookiesInterceptor())
                    .build();
            Log.i("AAA","只讀不寫");
        }
        if (isSaveCookie && !isReadCookie) {
            httpClient = new OkHttpClient.Builder()
                    .addInterceptor(new SaveCookiesInterceptor())
                    .build();
            Log.i("AAA","只寫不讀");
        }
        if (isSaveCookie && isReadCookie) {
            httpClient = new OkHttpClient.Builder()
                    .addInterceptor(new SaveCookiesInterceptor()).addInterceptor(new ReadCookiesInterceptor())
                    .build();
            Log.i("AAA","又寫又讀");
        } if (!isSaveCookie && !isReadCookie){
            httpClient = new OkHttpClient.Builder()
                    .build();
            Log.i("AAA","不寫不讀");
        }
        //指定客戶端
        Retrofit retrofit = new Retrofit.Builder().baseUrl(baseUrl).client(httpClient).addConverterFactory(ScalarsConverterFactory.create()).build();
  • 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
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 好了,暫時寫到這裡,以上就是對Retrofit的一個簡易封裝,當然網上也有一些大神對Retrofit進行了封裝。