Retrofit2

1.Retrofit2概述

  1. Retrofit框架是Square公司出品的目前非常流行的網(wǎng)絡框架.
    效率高遵湖,實現(xiàn)簡單,運用注解和動態(tài)代理.
    極大簡化了網(wǎng)絡請求的繁瑣步驟罗侯,非常適合REST ful網(wǎng)絡請求.
    目前Retofit版本是2

  2. Retrofit其實我們可以理解為OkHttp的加強版仑撞。
    它也是一個網(wǎng)絡加載框架聋袋。底層是使用OKHttp封裝的突倍。
    準確來說,網(wǎng)絡請求的工作本質上是OkHttp完成腔稀,而 Retrofit 僅負責網(wǎng)絡請求接口的封裝。
    它的一個特點是包含了特別多注解赘方,方便簡化你的代碼量烧颖。
    并且還支持很多的開源庫(著名例子:Retrofit + RxJava)

2.Retrofit2的好處

  1. 超級解耦
    解耦弱左?解什么耦窄陡?
    我們在請求接口數(shù)據(jù)的時候,API接口定義和API接口使用總是相互影響拆火,什么傳參跳夭、回調(diào)等涂圆,耦合在一塊。有時候我們會考慮一下怎么封裝我們的代碼讓這兩個東西不那么耦合币叹,這個就是Retrofit的解耦目標润歉,也是它的最大的特點。
  2. 可以配置不同HttpClient來實現(xiàn)網(wǎng)絡請求颈抚,如OkHttp踩衩、HttpClient...
  3. 支持同步、異步和RxJava
  4. 可以配置不同的反序列化工具來解析數(shù)據(jù)贩汉,如json驱富、xml...
  5. 請求速度快,使用非常方便靈活

3.Retrofit2配置

  1. 官網(wǎng)
  2. 依賴:
    implementation 'com.squareup.retrofit2:retrofit:2.5.0'
  3. 添加網(wǎng)絡權限:<uses-permission android:name="android.permission.INTERNET" />

4匹舞,Retrofit2的使用步驟

  1. 定義接口類(封裝URL地址和數(shù)據(jù)請求)
  2. 實例化Retrofit
  3. 通過Retrofit實例創(chuàng)建接口服務對象
  4. 接口服務對象調(diào)用接口中的方法褐鸥,獲取Call對象
  5. Call對象執(zhí)行請求(異步偏陪、同步請求)

6.Retrofit2發(fā)送GET锹安、POST請求(異步、同步)

  1. Retrofit2發(fā)送GET
//主機地址
String url = "http://apicloud.mob.com/appstore/health/search?key=1ac78a8602d58&name=轉氨酶";
    String BASE_URL = "http://apicloud.mob.com/appstore/health/";//必須以反斜杠結尾

    //接口服務
    public interface BigFlyServer {
        
        //GET
        @GET("search?key=1ac78a8602d58&name=轉氨酶")
        Call<ResponseBody> getData1();
    
        @GET("search?")
        Call<ResponseBody> getData2(@Query("key") String key,@Query("name") String key);
    
        @GET("search?")
        Call<ResponseBody> getData3(@QueryMap Map<String,Object> map);
    }


//Get異步
private void initGetEnqueue() {

    //1.創(chuàng)建Retrofit對象
        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl(MyServer.URL)
                .build();
        
        //2.獲取MyServer接口服務對象
        MyServer myServer = retrofit.create(MyServer.class);
        
        //3.獲取Call對象
        //方式一
        Call<ResponseBody> call1 = myServer.getData1();

        //方式二
        Call<ResponseBody> call2 = myServer.getData2("908ca46881994ffaa6ca20b31755b675");

        //方式三
        Map<String,Object> map = new HashMap<>();
        map.put("appKey","908ca46881994ffaa6ca20b31755b675");
        Call<ResponseBody> call = myServer.getData3(map);

        //4.Call對象執(zhí)行請求
        call.enqueue(new Callback<ResponseBody>() {

            @Override
            public void onResponse(Call<ResponseBody> call,Response<ResponseBody> response) {

                try {
                    String result = response.body().string();

                    Log.e("retrofit", "onResponse: "+result);
                    tv.setText(result);//默認直接回調(diào)主線程
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

            @Override
            public void onFailure(Call<ResponseBody> call, Throwable t) {

                Log.e("retrofit", "onFailure: "+t.getMessage());
            }
        });
    }


    //GET同步
    private void initGetExecute() {

        //1.創(chuàng)建Retrofit對象
        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl(MyServer.URL)
                .build();

        //2.獲取MyServer接口服務對象
        MyServer myServer = retrofit.create(MyServer.class);

        //3.獲取Call對象
        final Call<ResponseBody> call = myServer.getData1();

        new Thread(){//子線程執(zhí)行
            @Override
            public void run() {
                super.run();

                try {
        //4.Call對象執(zhí)行請求
                    Response<ResponseBody> response = call.execute();

                    final String result = response.body().string();

                    Log.e("retrofit", "onResponse: "+result);

                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            tv.setText(result);
                        }
                    });
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }.start();

    }

2.Retrofit2發(fā)送POST

String URL = "http://apicloud.mob.com/appstore/health/";//必須以反斜杠結尾

public interface MyServer {
    
//POST("search?")    POST("search")相同
    @POST("search?")
    @FormUrlEncoded
    Call<ResponseBody> postData1(@Field("key") String appKey,@Field("name") String appKey);

    @POST("search")  
    @FormUrlEncoded
    Call<ResponseBody> postData2(@FieldMap Map<String,Object> map);
}

//POST異步
private void initPostEnqueue() {

    //1.創(chuàng)建Retrofit對象
    Retrofit retrofit = new Retrofit.Builder()
            .baseUrl(MyServer.URL)
            .build();

    //2.獲取MyServer接口服務對象
    MyServer myServer = retrofit.create(MyServer.class);

    //3.獲取Call對象
    //方式一
    Call<ResponseBody> call1 = myServer.postData1("908ca46881994ffaa6ca20b31755b675");

    //方式二
    Map<String,Object> map = new HashMap<>();
    map.put("appKey","908ca46881994ffaa6ca20b31755b675");
    Call<ResponseBody> call = myServer.postData2(map);

    //4.Call對象執(zhí)行請求
    call.enqueue(new Callback<ResponseBody>() {
        @Override
        public void onResponse(Call<ResponseBody> call,Response<ResponseBody> response) {

            try {
                String result = response.body().string();

                Log.e("retrofit", "onResponse: "+result);
                tv.setText(result);//默認直接回調(diào)主線程
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        @Override
        public void onFailure(Call<ResponseBody> call, Throwable t) {

            Log.e("retrofit", "onFailure: "+t.getMessage());
        }
    });
}

7.Retrofit注解

注解代碼       請求格式

請求方式:
    @GET           GET請求
    @POST          POST請求
    @DELETE        DELETE請求
    @HEAD          HEAD請求
    @OPTIONS       OPTIONS請求
    @PATCH         PATCH請求

請求頭:
    @Headers("K:V") 添加請求頭详炬,作用于方法
    @Header("K")    添加請求頭姊舵,參數(shù)添加頭
    @FormUrlEncoded 用表單數(shù)據(jù)提交晰绎,搭配參數(shù)使用
    @Stream         下載
    @Multipart      用文件上傳提交   multipart/form-data

請求參數(shù):
    @Query          替代參數(shù)值,通常是結合get請求的
    @QueryMap       替代參數(shù)值括丁,通常是結合get請求的
    @Field          替換參數(shù)值寒匙,是結合post請求的
    @FieldMap       替換參數(shù)值,是結合post請求的

請求路徑:
    @Path           替換路徑
    @Url            路徑拼接

請求體:
    @Body(RequestBody)  設置請求體躏将,是結合post請求的

文件處理:
    @Part Multipart.Part
    @Part("key") RequestBody requestBody(單參)
    @PartMap Map<String,RequestBody> requestBodyMap(多參)
    @Body RequestBody requestBody(自定義參數(shù))

8.Retrofit2其他常用注解使用

String URL = "http://api.shujuzhihui.cn/api/news/";//必須以反斜杠結尾

public interface MyServer {
    
    //Path锄弱,不能替換參數(shù),必須路徑中字符
    @GET("wages/{wageId}/detail") 
    Call<ResponseBody >getImgData(@Path("wageId") String wageId);

    //Url
            //@Url cannot be used with @GET URL (parameter #1)祸憋,如果使用url注解会宪,get注解為空
    @GET
    Call<ResponseBody >getImgData(@Url String url);

    @GET
    Call<ResponseBody >getImgData(@Url String url,@Query("appKey") String appkey);

    
    //Json
    @POST("categories")
    @Headers("Content-Type:application/json")
    Call<ResponseBody> getFormDataJson(@Body RequestBody requestBody);

    //Form
    @POST("categories")
    @Headers("Content-Type:application/x-www-form-urlencoded")
    Call<ResponseBody> getFormData1(@Body RequestBody requestBody);

    //復用URL
    @POST()
    @Headers("Content-Type:application/x-www-form-urlencoded")
    Call<ResponseBody> getFormData2(@Url String url,@Body RequestBody requestBody);

    //通用
    @POST()
    Call<ResponseBody> getFormData3(@Url String url, @Body RequestBody requestBody, @Header("Content-Type") String contentType);
}

//RequestBody參數(shù)拼接
private void initPostBody() {

    Retrofit.Builder builder = new Retrofit.Builder();
    Retrofit retrofit = builder.baseUrl(MyServer.URL)
            .build();

    MyServer myServer = retrofit.create(MyServer.class);

    //Json類型
    String json1 = "{\n" + "    \"appKey\": \"908ca46881994ffaa6ca20b31755b675\"\n" +  "}";
    RequestBody requestBody01 = RequestBody.create(MediaType.parse("application/json,charset-UTF-8"),json1);
    Call<ResponseBody> call01 = myServer.getFormDataJson(requestBody01);

    //String類型
    //有參形式
    RequestBody requestBody02 = RequestBody.create(MediaType.parse("application/x-www-form-urlencoded,charset-UTF-8"),"appKey=908ca46881994ffaa6ca20b31755b675");
    Call<ResponseBody> call02 = myServer.getFormData1(requestBody02);

    //無參形式
    RequestBody requestBody3 = RequestBody.create(MediaType.parse("application/x-www-form-urlencoded,charset-UTF-8"),"");
    Call<ResponseBody> call03 = myServer.getFormData1(requestBody3);

    //RequestBody (Form表單,鍵值對參數(shù)形式)
    //方式一(requestBody)
    FormBody requestBody = new FormBody.Builder()
            .add("appKey","908ca46881994ffaa6ca20b31755b675")
            .build();
    Call<ResponseBody> call1 = myServer.getFormData1(requestBody);

    //方式二(url+requestBody)
    FormBody requestBody = new FormBody.Builder()
            .add("appKey","908ca46881994ffaa6ca20b31755b675")
            .build();
    Call<ResponseBody> call2 = myServer.getFormData2("categories",requestBody);

    //方式三(url+requestBody+header)
    FormBody requestBody = new FormBody.Builder()
            .add("appKey","908ca46881994ffaa6ca20b31755b675")
            .build();
    Call<ResponseBody> call3 = myServer.getFormData3("categories",requestBody,"application/x-www-form-urlencoded");


    call3.enqueue(new Callback<ResponseBody>() {
        @Override
        public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {

            try {
                String result = response.body().string();

                Log.e("retrofit", "onResponse: "+result);
                tv.setText(result);//默認直接回調(diào)主線程
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        @Override
        public void onFailure(Call<ResponseBody> call, Throwable t) {

            Log.e("retrofit", "onFailure: "+t.getMessage());
        }
    });
}

9.數(shù)據(jù)解析器(Converter)

  • Retrofit支持多種數(shù)據(jù)解析方式
  • 使用時需要在Gradle添加依賴
    Gson:com.squareup.retrofit2:converter-gson:2.0.2
    Jackson:com.squareup.retrofit2:converter-jackson:2.0.2
Retrofit retrofit = new Retrofit.Builder()
                .addConverterFactory(GsonConverterFactory.create())
                .baseUrl(MyService.URL)
                .build();

10.網(wǎng)絡請求適配器(CallAdapter)

  • Retrofit支持多種網(wǎng)絡請求適配器方式:guava蚯窥、Java8和rxjava
    guava:com.squareup.retrofit2:adapter-guava:2.0.2
    Java8:com.squareup.retrofit2:adapter-java8:2.0.2
    rxjava:com.squareup.retrofit2:adapter-rxjava:2.0.2

11.Retrofit2文件上傳

String FileUpLoadURL = "http://yun918.cn/study/public/";

public interface MyServer {
    
 @POST("file_upload.php")
    @Multipart
    Call<ResponseBody> upLoadFile1(@Part MultipartBody.Part part,@Part("key") RequestBody requestBody);//單參

    @POST("file_upload.php")
    @Multipart
    Call<ResponseBody> upLoadFile2(@Part MultipartBody.Part part, @PartMap Map<String,RequestBody> requestBodyMap); //多參

    @POST("file_upload.php")
    @Multipart
    Call<ResponseBody> upLoadFile3(@Body RequestBody requestBody);  //自定義
}

//文件上傳
private void initPostFile() {

    Retrofit retrofit = new Retrofit.Builder()
            .baseUrl(MyServer.FileUpLoadURL)
            .build();

    MyServer myServer = retrofit.create(MyServer.class);

    Call<ResponseBody> call = null;

    //上傳文件路徑
    File file = new File("/sdcard/Pictures/Screenshorts/dd.png");
    if(file.exists()){

        //方式一
        RequestBody requestBody1 = RequestBody.create(MediaType.parse("image/png"),file);

        MultipartBody.Part part = MultipartBody.Part.createFormData("file", file.getName(), requestBody1);

        RequestBody responseBody2 = RequestBody.create(MediaType.parse("multipart/form-data"),"abc");

        call = myServer.upLoadFile1(part, responseBody2);

        //方式二
        MultipartBody.Builder builder1 = new MultipartBody.Builder().setType(MultipartBody.FORM);

        MultipartBody body = builder1.addFormDataPart("key", "abc")
                .addFormDataPart("file", file.getName(), RequestBody.create(MediaType.parse("image/png"),file))
                .build();

        call = myServer.upLoadFile3(body);

        //方式三
        MultipartBody.Part part2 = MultipartBody.Part.createFormData("file", file.getName(), RequestBody.create(MediaType.parse("image/png"),file));

        Map<String, RequestBody> map = new HashMap<>();
        RequestBody responseBody3 = RequestBody.create(MediaType.parse("multipart/form-data"),"abc");
        map.put("key",responseBody3);

        call = myServer.upLoadFile2(part2, map);

    }

    call.enqueue(new Callback<ResponseBody>() {
        @Override
        public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
            try {
                String result = response.body().string();

                Log.e("retrofit", "onResponse: "+result);
                tv.setText(result);//默認直接回調(diào)主線程
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        @Override
        public void onFailure(Call<ResponseBody> call, Throwable t) {
            Log.e("retrofit", "onFailure: "+t.getMessage());
        }
    });
}

12.Form表單語法

1掸鹅、Form表單語法

在Form元素的語法中,EncType表明提交數(shù)據(jù)的格式 用 Enctype 屬性指定將數(shù)據(jù)回發(fā)到服務器時瀏覽器使用的編碼類型拦赠。
1巍沙,application/x-www-form-urlencoded: 窗體數(shù)據(jù)被編碼為名稱/值對。這是標準的編碼格式荷鼠。
2句携,multipart/form-data: 窗體數(shù)據(jù)被編碼為一條消息,頁上的每個控件對應消息中的一個部分允乐,這個一般文件上傳時用矮嫉。
3削咆,text/plain: 窗體數(shù)據(jù)以純文本形式進行編碼,其中不含任何控件或格式字符蠢笋。

2拨齐、常用的編碼方式

form的enctype屬性為編碼方式,常用有兩種:
application/x-www-form-urlencoded(默認)
multipart/form-data
1.x-www-form-urlencoded
瀏覽器用x-www-form-urlencoded的編碼方式把form數(shù)據(jù)轉換成一個字串(name1=value1&name2=value2…)
2.multipart/form-data
瀏覽器把form數(shù)據(jù)封裝到http body中昨寞,然后發(fā)送到server瞻惋。如果沒有type=file的控件,用默認的application/x-www-form-urlencoded就可以了援岩。但是如果type=file的話熟史,就要用到multipart/form-data了。

11.Retrofit2及OkHttp3的區(qū)別

Retrofit2使用注解設置請求內(nèi)容
Retrofit2回調(diào)主線程窄俏,OkHttp3回調(diào)子線程
Retrofit2可以做數(shù)據(jù)解析轉換
Retrofit2可以使用在REST ful網(wǎng)絡請求.

12.Retrofit2源碼分析(底層OkHttp3蹂匹,注解了解,反射了解)

構建者構建
動態(tài)代理凹蜈、反射
注解配置請求
底層基于OkHttpCall調(diào)用

源碼解析:
1.點擊builder限寞,平臺選擇(platform)、獲取工廠仰坦、baseURL

platform = Platform.get();
callFactory = retrofit.callFactory;
baseUrl = retrofit.baseUrl;

2.點擊build方法

 if (baseUrl == null) {
        throw new IllegalStateException("Base URL required.");
      }

//可以選擇客戶端履植,如果傳的callFactory是空,默認創(chuàng)建一個ok  
okhttp3.Call.Factory callFactory = this.callFactory;
      if (callFactory == null) {
        callFactory = new OkHttpClient();
      }

//線程池悄晃,主要做線程切換
Executor callbackExecutor = this.callbackExecutor;
      if (callbackExecutor == null) {
        callbackExecutor = platform.defaultCallbackExecutor();
      }

 // 添加一個網(wǎng)絡切換器
      List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(this.callAdapterFactories);
      callAdapterFactories.addAll(platform.defaultCallAdapterFactories(callbackExecutor));

// 添加一個數(shù)據(jù)切換工廠
List<Converter.Factory> converterFactories = new ArrayList<>(
          1 + this.converterFactories.size() + platform.defaultConverterFactoriesSize());

//最后添加完工廠返回一個retrofit對象
`
return new Retrofit(callFactory, baseUrl, unmodifiableList(converterFactories),
          unmodifiableList(callAdapterFactories), callbackExecutor, validateEagerly);
  1. MyService myService = retrofit.create(MyService.class);
    用到了動態(tài)代理(Proxy.newProxyInstance)及反射

Proxy.newProxyInstance獲取動態(tài)代理單例玫霎,里邊有三個參數(shù),
第一個是代理對象妈橄,第二個參數(shù)是調(diào)用的方法庶近,第三個是方法的參數(shù)
return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },
        new InvocationHandler() {
          private final Platform platform = Platform.get();
          private final Object[] emptyArgs = new Object[0];

          @Override public Object invoke(Object proxy, Method method, @Nullable Object[] args)
              throws Throwable {
            // If the method is a method from Object then defer to normal invocation.
            if (method.getDeclaringClass() == Object.class) {
              return method.invoke(this, args);
            }
            if (platform.isDefaultMethod(method)) {
              return platform.invokeDefaultMethod(method, service, proxy, args);
            }
            return loadServiceMethod(method).invoke(args != null ? args : emptyArgs);
          }
        });


 ServiceMethod<?> loadServiceMethod(Method method) {
    ServiceMethod<?> result = serviceMethodCache.get(method);
    if (result != null) return result;

    synchronized (serviceMethodCache) {
      result = serviceMethodCache.get(method);
      if (result == null) {
        result = ServiceMethod.parseAnnotations(this, method);
        serviceMethodCache.put(method, result);
      }
    }
    return result;
  }


result = ServiceMethod.parseAnnotations(this, method);
進方法里邊看,RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method);
工廠模式眷蚓,看工廠是這么build出來的
遍歷注解


ServiceMethod中返回的東西

HttpServiceMethod

 @Override ReturnT invoke(Object[] args) {
    return callAdapter.adapt(
        new OkHttpCall<>(requestFactory, args, callFactory, responseConverter));
  }


OkHttpCall----enqueue-- response = parseResponse(rawResponse);

T body = responseConverter.convert(catchingBody);

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末鼻种,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子沙热,更是在濱河造成了極大的恐慌叉钥,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,599評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件篙贸,死亡現(xiàn)場離奇詭異投队,居然都是意外死亡,警方通過查閱死者的電腦和手機爵川,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,629評論 3 385
  • 文/潘曉璐 我一進店門敷鸦,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事轧膘〕” “怎么了兔甘?”我有些...
    開封第一講書人閱讀 158,084評論 0 348
  • 文/不壞的土叔 我叫張陵谎碍,是天一觀的道長。 經(jīng)常有香客問我洞焙,道長蟆淀,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,708評論 1 284
  • 正文 為了忘掉前任澡匪,我火速辦了婚禮熔任,結果婚禮上,老公的妹妹穿的比我還像新娘唁情。我一直安慰自己疑苔,他們只是感情好,可當我...
    茶點故事閱讀 65,813評論 6 386
  • 文/花漫 我一把揭開白布甸鸟。 她就那樣靜靜地躺著惦费,像睡著了一般。 火紅的嫁衣襯著肌膚如雪抢韭。 梳的紋絲不亂的頭發(fā)上薪贫,一...
    開封第一講書人閱讀 50,021評論 1 291
  • 那天,我揣著相機與錄音刻恭,去河邊找鬼瞧省。 笑死,一個胖子當著我的面吹牛鳍贾,可吹牛的內(nèi)容都是我干的鞍匾。 我是一名探鬼主播,決...
    沈念sama閱讀 39,120評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼骑科,長吁一口氣:“原來是場噩夢啊……” “哼候学!你這毒婦竟也來了?” 一聲冷哼從身側響起纵散,我...
    開封第一講書人閱讀 37,866評論 0 268
  • 序言:老撾萬榮一對情侶失蹤梳码,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后伍掀,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體掰茶,經(jīng)...
    沈念sama閱讀 44,308評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,633評論 2 327
  • 正文 我和宋清朗相戀三年蜜笤,在試婚紗的時候發(fā)現(xiàn)自己被綠了濒蒋。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,768評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖沪伙,靈堂內(nèi)的尸體忽然破棺而出瓮顽,到底是詐尸還是另有隱情,我是刑警寧澤围橡,帶...
    沈念sama閱讀 34,461評論 4 333
  • 正文 年R本政府宣布暖混,位于F島的核電站,受9級特大地震影響翁授,放射性物質發(fā)生泄漏拣播。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 40,094評論 3 317
  • 文/蒙蒙 一收擦、第九天 我趴在偏房一處隱蔽的房頂上張望贮配。 院中可真熱鬧,春花似錦塞赂、人聲如沸泪勒。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,850評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽圆存。三九已至,卻和暖如春鳍置,著一層夾襖步出監(jiān)牢的瞬間辽剧,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,082評論 1 267
  • 我被黑心中介騙來泰國打工税产, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留怕轿,地道東北人。 一個月前我還...
    沈念sama閱讀 46,571評論 2 362
  • 正文 我出身青樓辟拷,卻偏偏與公主長得像撞羽,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子衫冻,可洞房花燭夜當晚...
    茶點故事閱讀 43,666評論 2 350

推薦閱讀更多精彩內(nèi)容

  • 本博客為作者原創(chuàng)诀紊,如需轉載請注明原博客出處:WONDER'TWO 0X00 寫在前面 相信做過And...
    一只酸奶牛哇閱讀 4,352評論 9 34
  • 前言 如果看Retrofit的源碼會發(fā)現(xiàn)其實質上就是對okHttp的封裝,使用面向接口的方式進行網(wǎng)絡請求隅俘,利用動態(tài)...
    李某人吖閱讀 2,035評論 0 0
  • 一.Retrofit中Builder模式完成初始化工作 Retrofit現(xiàn)在已經(jīng)是各種網(wǎng)絡請求類APP的標配了邻奠,我...
    Geeks_Liu閱讀 2,017評論 0 9
  • 本文將順著構建請求對象->構建請求接口->發(fā)起同步/異步請求的流程,分析Retrofit是如何實現(xiàn)的为居。 開始之前碌宴,...
    zhuhf閱讀 1,610評論 0 10
  • 前言 注解式的框架非常火蒙畴,注解以其輕量贰镣,簡潔等特性被人們所喜愛者呜象,關鍵是它解藕。網(wǎng)絡請求的框架非常多碑隆,比較受歡迎的...
    薩達哈魯醬閱讀 568評論 0 5