Retrofit源碼解析

前邊OkHttp的源碼順藤摸瓜校赤,摸了個(gè)遍堡牡。但是我們用的比較多的還是Retrofit则涯,都是square的佳作复局,它是在OKHttp上進(jìn)行了封裝,對(duì)開(kāi)發(fā)者變得更加友好粟判。本文基于retrofit: 2.9.0開(kāi)擼。

一、Retrofit在OKHttp上新增了什么魔法

  • 使用動(dòng)態(tài)代理模式使用接口和注解方式定義請(qǐng)求方法赎败,對(duì)應(yīng)用層友好赚抡,使用容易理解和方便
  • 它可以和RxJava配合使用,超級(jí)解耦
  • 它可以定制很多解析轉(zhuǎn)換器呻澜,來(lái)將接口返回的數(shù)據(jù)封裝為我們的JavaBean對(duì)象
  • 在請(qǐng)求回來(lái)后递礼,它會(huì)自動(dòng)切換為主線程,無(wú)需額外在應(yīng)用內(nèi)部進(jìn)行線程的切換

二羹幸、Retrofit的基本用法

Retrofit用法其實(shí)也不用多講脊髓,很簡(jiǎn)單:

    1. 首先,新建個(gè)請(qǐng)求接口類(lèi)
interface TestRetrofitService {

    @GET("test")
    fun getTestParms(): Call<ResponseBody>
}
    1. 再構(gòu)建一個(gè)全局的Retrofit實(shí)例栅受,它也是基于建造者模式
var retrofit: Retrofit = Retrofit.Builder().baseUrl("http://www.baidu.com").build()
    1. 然后使用Retrofit實(shí)例動(dòng)態(tài)生成一個(gè)請(qǐng)求接口的代理對(duì)象
var testRetrofitService: TestRetrofitService = retrofit.create(TestRetrofitService::class.java)

*4. 使用代理對(duì)象調(diào)用請(qǐng)求接口方法将硝,生成一個(gè)Call對(duì)象

val testCall: Call = testRetrofitService.getBaiduParms();
    1. 調(diào)用Call的enqueue方法,發(fā)起異步請(qǐng)求屏镊,execute方法則是同步請(qǐng)求
     testCall.enqueue(object: retrofit2.Callback<ResponseBody>{
            override fun onFailure(call: retrofit2.Call<ResponseBody>, t: Throwable) {
                TODO("Not yet implemented")
            }

            override fun onResponse(call: retrofit2.Call<ResponseBody>, response: retrofit2.Response<ResponseBody>) {
                TODO("Not yet implemented")
            }

        })

三依疼、Retrofit是如何通過(guò)建造者模式實(shí)例化的?

Retrofit.Builder().baseUrl("http://www.baidu.com").build()
    1. Retrofit有個(gè)Builder內(nèi)部類(lèi)而芥,它有兩個(gè)構(gòu)造方法律罢,它會(huì)傳入平臺(tái)類(lèi),并通過(guò)jvm虛擬機(jī)的名字判斷是Android平臺(tái)還是Java平臺(tái)棍丐。
   Builder(Platform platform) {
      this.platform = platform;
    }

    public Builder() {
      this(Platform.get());
    }
  private static Platform findPlatform() {
    return "Dalvik".equals(System.getProperty("java.vm.name"))
        ? new Android() //
        : new Platform(true);
  }
    1. 然后通過(guò)Retrofit.Builder實(shí)例可以傳入很多配置參數(shù)误辑,這和OKHttp一致,最后通過(guò)build()方法骄酗,實(shí)例化Retrofit
    public Retrofit build() {
      if (baseUrl == null) {
        throw new IllegalStateException("Base URL required.");
      }

      ...

      return new Retrofit(
          callFactory,
          baseUrl,
          unmodifiableList(converterFactories),
          unmodifiableList(callAdapterFactories),
          callbackExecutor,
          validateEagerly);
    }

四稀余、Retrofit是如何通過(guò)動(dòng)態(tài)代理實(shí)例化請(qǐng)求接口類(lèi)的代理對(duì)象?

//請(qǐng)求接口類(lèi)
interface TestRetrofitService {

    @GET("meinv")
    fun getBaiduParms(): Call<ResponseBody>
}

//通過(guò)動(dòng)態(tài)代理實(shí)例化一個(gè)代理對(duì)象
var testRetrofitService = retrofit.create(TestRetrofitService::class.java)

跟蹤Retrofit.create()方法趋翻,映入眼前的就是妥妥的動(dòng)態(tài)代理模式了睛琳,Proxy.newProxyInstance()盒蟆。通過(guò)動(dòng)態(tài)代理返回了一個(gè)TestRetrofitService接口類(lèi)的代理對(duì)象

  public <T> T create(final Class<T> service) {
    return (T)
        Proxy.newProxyInstance(
            service.getClassLoader(),
            new Class<?>[] {service},
            new InvocationHandler() {
              ...
              @Override
              public @Nullable Object invoke(Object proxy, Method method, @Nullable Object[] args)
                  throws Throwable {
                ...
158行                return platform.isDefaultMethod(method)
                    ? platform.invokeDefaultMethod(method, service, proxy, args)
                    : loadServiceMethod(method).invoke(args);
              }
            });
  }

五、Retrofit生成的動(dòng)態(tài)代理對(duì)象調(diào)用請(qǐng)求方法后师骗,如何返回的Call對(duì)象的历等?

val testCall: Call = testRetrofitService.getBaiduParms();

    1. 我們可以看到上面動(dòng)態(tài)代理158行,這里又是Android和java平臺(tái)的判斷辟癌,這里直接可以看到
loadServiceMethod(method).invoke(args)
    1. 在loadServiceMethod()方法中寒屯,它將對(duì)傳入的Method的注解進(jìn)行解析保存為一個(gè)ServiceMethod對(duì)象并緩存起來(lái)。
  ServiceMethod<?> loadServiceMethod(Method method) {
    //1. 首先沖緩存中獲取黍少,獲取到了就返回
    ServiceMethod<?> result = serviceMethodCache.get(method);
    if (result != null) return result;

    //2. 為了線程安全問(wèn)題寡夹,加了鎖
    synchronized (serviceMethodCache) {
      result = serviceMethodCache.get(method);
      if (result == null) {
        //3. 開(kāi)始解析Annotations
        result = ServiceMethod.parseAnnotations(this, method);
        //4. 將解析好的serviceMethod緩存起來(lái)
        serviceMethodCache.put(method, result);
      }
    }
    return result;
  }
    1. ServiceMethod是一個(gè)抽象類(lèi),HttpServiceMethod為其子類(lèi)
static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) {
26行    RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method);

    Type returnType = method.getGenericReturnType();
   ...

    return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);
  }
    1. 如上26行厂置,它通過(guò)RequestFactory類(lèi)的parseAnnotations()方法解析請(qǐng)求接口類(lèi)的方法上和參數(shù)的注解菩掏。

在RequestFactory里實(shí)際也是通過(guò)建造者模式,返回了RequestFactory實(shí)例

 static RequestFactory parseAnnotations(Retrofit retrofit, Method method) {
    return new Builder(retrofit, method).build();
  }

通過(guò)查看Builder內(nèi)部類(lèi)中的build方法昵济,發(fā)現(xiàn)了很多解析Annotation注解的方法智绸。

    RequestFactory build() {
      for (Annotation annotation : methodAnnotations) {
181行        parseMethodAnnotation(annotation);
      }
      ...

      int parameterCount = parameterAnnotationsArray.length;
      parameterHandlers = new ParameterHandler<?>[parameterCount];
      for (int p = 0, lastParameter = parameterCount - 1; p < parameterCount; p++) {
205行        parameterHandlers[p] =
            parseParameter(p, parameterTypes[p], parameterAnnotationsArray[p], p == lastParameter);
      }

     ...
      return new RequestFactory(this);
    }

181行解析的是方法上的注解:這里大家看著都懂,無(wú)非就是解析方法上的一個(gè)@GET访忿、@POST等注解瞧栗,并獲取值,并保存在成員變量中

private void parseMethodAnnotation(Annotation annotation) {
      if (annotation instanceof DELETE) {
        parseHttpMethodAndPath("DELETE", ((DELETE) annotation).value(), false);
      } else if (annotation instanceof GET) {
        parseHttpMethodAndPath("GET", ((GET) annotation).value(), false);
      }
  ...
}

205行解析的是方法上的注解:這里就是將方法里的每個(gè)參數(shù)單獨(dú)保存為一個(gè)ParameterHandler實(shí)例

    private @Nullable ParameterHandler<?> parseParameter(
        int p, Type parameterType, @Nullable Annotation[] annotations, boolean allowContinuation) {
      ParameterHandler<?> result = null;
      if (annotations != null) {
        for (Annotation annotation : annotations) {
          ParameterHandler<?> annotationAction =
              parseParameterAnnotation(p, parameterType, annotations, annotation);
   ...
}

后續(xù)的如何解析海铆,大家可以深入代碼中看看迹恐,這里就不一一貼代碼了。比較簡(jiǎn)單游添,就是注解的解析取值系草,存值過(guò)程。

    1. 前邊的ServiceMethod.parseAnnotations()方法最終返回了一個(gè)HttpServiceMethod實(shí)例唆涝,而HttpserviceMethod是ServiceMethod的子類(lèi)
 static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) {
    RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method);
    ...
    return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);
  }
    1. 回到第2點(diǎn)找都,動(dòng)態(tài)代理最終返回的是loadServiceMethod(method).invoke(args),而loadServiceMethod(method)返回的是一個(gè)HttpServiceMethod的實(shí)例廊酣,我們看看它的invoke()方法能耻,這里就實(shí)例化了一個(gè)OKHttpCall對(duì)象,而它就是Call的子類(lèi)亡驰。這里其實(shí)它還被另外一個(gè)ExecutorCallbackCall包裝了一層(adapt(call, args)方法包裝)晓猛。這里先不講。
  final @Nullable ReturnT invoke(Object[] args) {
    Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);
    return adapt(call, args);
  }

六凡辱、Retrofit如何通過(guò)Call實(shí)例對(duì)象發(fā)起請(qǐng)求的戒职?

   testCall.enqueue(object: retrofit2.Callback<ResponseBody>{
        override fun onFailure(call: retrofit2.Call<ResponseBody>, t: Throwable) {
            TODO("Not yet implemented")
        }

        override fun onResponse(call: retrofit2.Call<ResponseBody>, response: retrofit2.Response<ResponseBody>) {
            TODO("Not yet implemented")
        }

    })

前面知道了其實(shí)真正執(zhí)行請(qǐng)求的Call就是OKHttpCall,我們跟蹤enqueue()方法進(jìn)去看看透乾。

    1. 調(diào)用OKHttpCall.enqueue()方法
  @Override
  public void enqueue(final Callback<T> callback) {
    okhttp3.Call call;
    synchronized (this) {
      call = rawCall;
      if (call == null && failure == null) {
        try {
130行          call = rawCall = createRawCall();
        } catch (Throwable t) {
        }
      }
    }

147行    call.enqueue(
        new okhttp3.Callback() {
          @Override
          public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse) {
              callback.onResponse(OkHttpCall.this, response);
          }

          @Override
          public void onFailure(okhttp3.Call call, IOException e) {
            callback.onFailure(OkHttpCall.this, e);
          }
        });
  }
    1. 它在130行調(diào)用了createRawCall()方法洪燥,它調(diào)用了callFactory.newCall方法創(chuàng)建出okHttp3.Call對(duì)象
private okhttp3.Call createRawCall() throws IOException {
    okhttp3.Call call = callFactory.newCall(requestFactory.create(args));
   ...
    return call;
  }
    1. 這里的callFactory實(shí)際上就是OKHttpClient磕秤,這在之前建造者模式創(chuàng)建Retrofit實(shí)例的build()方法中可以看到,而OkHttpClient.newCall()方法實(shí)際上就是返回了一個(gè)RealCall對(duì)象
public Retrofit build(){
      okhttp3.Call.Factory callFactory = this.callFactory;
      if (callFactory == null) {
        callFactory = new OkHttpClient();
      }
...
}
  @Override public Call newCall(Request request) {
    return RealCall.newRealCall(this, request, false /* for web socket */);
  }
    1. requestFactory.create(args)方法呢捧韵,就是返回了一個(gè)Request請(qǐng)求對(duì)象市咆。
  okhttp3.Request create(Object[] args) throws IOException {
    @SuppressWarnings("unchecked") // It is an error to invoke a method with the wrong arg types.
    ...

    RequestBuilder requestBuilder =
        new RequestBuilder(
            httpMethod,
            baseUrl,
            relativeUrl,
            headers,
            contentType,
            hasBody,
            isFormEncoded,
            isMultipart);

    ...

    return requestBuilder.get().tag(Invocation.class, new Invocation(method, argumentList)).build();
  }
    1. 回到1中的147行,call.enqueue()實(shí)際就是使用OKHttp的ReallCall對(duì)象開(kāi)始將請(qǐng)求進(jìn)行分發(fā)再来,或加入執(zhí)行隊(duì)列或加入等待隊(duì)列蒙兰。這里和之前寫(xiě)的《OKHttp源碼解析》請(qǐng)求流程一致了。然后在回調(diào)接口芒篷。

七搜变、Retrofit如何在返回response時(shí),切換到主線程可以直接渲染UI的梭伐?

這里講起來(lái)有點(diǎn)繞:

    1. 先回到Retrofit的創(chuàng)建來(lái)痹雅,在Build.buid()方法中,它會(huì)為Retrofit默認(rèn)添加平臺(tái)默認(rèn)的CallAdapter適配器工廠糊识,如android平臺(tái)就添加Android類(lèi)中的callbackExecutor(PS: Android是platform的子類(lèi),實(shí)現(xiàn)了defaultCallbackExecutor方法)
public Retrofit build() {
...
 Executor callbackExecutor = this.callbackExecutor;
      if (callbackExecutor == null) {
631行        callbackExecutor = platform.defaultCallbackExecutor();
      }
      638行 callAdapterFactories.addAll(platform.defaultCallAdapterFactories(callbackExecutor));
...
}
    1. 631行獲取了平臺(tái)默認(rèn)的回調(diào)執(zhí)行器摔蓝,這里就是線程切換的地方赂苗,而Android是Platform內(nèi)部子類(lèi)。它返回了一個(gè)MainThreadExecutor()對(duì)象贮尉,而它實(shí)際上就是通過(guò)new Handler(Looper.getMainLooper())拌滋,Handler來(lái)實(shí)現(xiàn)切回主線程。
  static final class Android extends Platform {


    @Override
    public Executor defaultCallbackExecutor() {
      return new MainThreadExecutor();
    }

    static final class MainThreadExecutor implements Executor {
      private final Handler handler = new Handler(Looper.getMainLooper());

      @Override
      public void execute(Runnable r) {
        handler.post(r);
      }
    }
  }

八. 實(shí)際上這里已經(jīng)知道Retrofit怎么切換到主線程了猜谚,那么它在哪里調(diào)用的呢败砂?

    1. 在 上面七的638行,platform.defaultCallAdapterFactories(callbackExecutor)它通過(guò)傳入callBackExecuter魏铅,返回了一個(gè)平臺(tái)默認(rèn)的CallAdapterFactory適配器工廠昌犹。它實(shí)際上就是返回了一個(gè)DefaultCallAdapterFactory。
  List<? extends CallAdapter.Factory> defaultCallAdapterFactories(
      @Nullable Executor callbackExecutor) {
    DefaultCallAdapterFactory executorFactory = new DefaultCallAdapterFactory(callbackExecutor);
    return hasJava8Types
        ? asList(CompletableFutureCallAdapterFactory.INSTANCE, executorFactory)
        : singletonList(executorFactory);
  }
    1. 前邊我們說(shuō)在HttpServiceMethod.invoke()返回的是一個(gè)OKHttpCall對(duì)象览芳,其實(shí)不完全對(duì)斜姥,因?yàn)樗€被CallAdapter適配器包裝了一層。
  @Override
  final @Nullable ReturnT invoke(Object[] args) {
    Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);
    return adapt(call, args);
  }

    @Override
    protected ReturnT adapt(Call<ResponseT> call, Object[] args) {
      return callAdapter.adapt(call);
    }
    1. 2中所說(shuō)的CallAdapter適配器就是通過(guò)DefaultCallAdapterFactory工廠的get()方法生成的沧竟。
      至于如何生成铸敏,給一個(gè)路線(是在動(dòng)態(tài)代理生成代理對(duì)象,并通過(guò)代理對(duì)象調(diào)用請(qǐng)求方法時(shí)):
1. ServiceMethod.parseAnnotations()
2.HttpServiceMethod.parseAnnotations()
    CallAdapter<ResponseT, ReturnT> callAdapter =
        createCallAdapter(retrofit, method, adapterType, annotations);
3. HttpServiceMethod.createCallAdapter()
4. Retrofit.callAdapter()
5. Retrofit.nextCallAdapter()
    public CallAdapter<?, ?> nextCallAdapter(
      CallAdapter.Factory skipPast, Type returnType, Annotation[] annotations) {
      ...
      for (int i = start, count = callAdapterFactories.size(); i < count; i++) {
        CallAdapter<?, ?> adapter = callAdapterFactories.get(i).get(returnType, annotations, this);
        return adapter;
     }
    }
    1. 看到DefaultCallAdapterFactory.get()方法悟泵,它返回了一個(gè)CallAdapter對(duì)象杈笔。
  public @Nullable CallAdapter<?, ?> get(
      Type returnType, Annotation[] annotations, Retrofit retrofit) {
    ...
 47行   final Executor executor =
        Utils.isAnnotationPresent(annotations, SkipCallbackExecutor.class)
            ? null
            : callbackExecutor;

    return new CallAdapter<Object, Call<?>>() {
      @Override
      public Type responseType() {
        return responseType;
      }

      @Override
      public Call<Object> adapt(Call<Object> call) {
        return executor == null ? call : new ExecutorCallbackCall<>(executor, call);
      }
    };
  }
    1. 47行:callbackExecutor實(shí)際就是1中的MainThreadExecutor,最后return CallAdapter糕非,在CallAdapter的adapt方法中返回了一個(gè)ExecutorCallbackCall對(duì)象
new ExecutorCallbackCall<>(executor, call)
    1. 這個(gè)傳入的參數(shù)call就是OKHttpCall, 而ExecutorCallbackCall就是包裝OKHttpCall的蒙具,它主要用來(lái)回調(diào)時(shí)做線程切換用途的敦第。它也是call的子類(lèi)。它是DefautlCallAdapterFactory內(nèi)部類(lèi)
 static final class ExecutorCallbackCall<T> implements Call<T> {

    @Override
    public void enqueue(final Callback<T> callback) {
      //1. delegate就是OKHttpCall店量,實(shí)際上就是OKHttpCall.enqueue()
      delegate.enqueue(
          new Callback<T>() {
            @Override
            public void onResponse(Call<T> call, final Response<T> response) {
              //2. 請(qǐng)求返回后使用MainThreadExecutor對(duì)象切換線程
              callbackExecutor.execute(
                  () -> {
                    if (delegate.isCanceled()) {
                      // cancellation.
                      callback.onFailure(ExecutorCallbackCall.this, new IOException("Canceled"));
                    } else {
                      callback.onResponse(ExecutorCallbackCall.this, response);
                    }
                  });
            }

            @Override
            public void onFailure(Call<T> call, final Throwable t) {
              callbackExecutor.execute(() -> callback.onFailure(ExecutorCallbackCall.this, t));
            }
          });
    }
}
  1. delegate就是OKHttpCall芜果,實(shí)際上就是OKHttpCall.enqueue()
  2. 請(qǐng)求返回后使用MainThreadExecutor對(duì)象切換線程
              callbackExecutor.execute(() -> callback.onFailure(ExecutorCallbackCall.this, t));

九、結(jié)語(yǔ)

我們通過(guò)Retrofit的主線了解清楚了融师,Retrofit如何通過(guò)動(dòng)態(tài)代理和注解反射等機(jī)制對(duì)OKHttp進(jìn)行封裝右钾。對(duì)于我們靈活使用Retrofit來(lái)開(kāi)發(fā)和解決使用Retrofit中遇到的問(wèn)題非常有幫助,另外也通過(guò)跟蹤框架源碼旱爆,對(duì)于搭建框架也有了更多的認(rèn)識(shí)和理論支撐舀射。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市怀伦,隨后出現(xiàn)的幾起案子脆烟,更是在濱河造成了極大的恐慌,老刑警劉巖房待,帶你破解...
    沈念sama閱讀 219,110評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件邢羔,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡桑孩,警方通過(guò)查閱死者的電腦和手機(jī)拜鹤,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,443評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)流椒,“玉大人敏簿,你說(shuō)我怎么就攤上這事⌒海” “怎么了惯裕?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,474評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)绣硝。 經(jīng)常有香客問(wèn)我蜻势,道長(zhǎng),這世上最難降的妖魔是什么域那? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,881評(píng)論 1 295
  • 正文 為了忘掉前任咙边,我火速辦了婚禮,結(jié)果婚禮上次员,老公的妹妹穿的比我還像新娘败许。我一直安慰自己,他們只是感情好淑蔚,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,902評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布市殷。 她就那樣靜靜地躺著,像睡著了一般刹衫。 火紅的嫁衣襯著肌膚如雪醋寝。 梳的紋絲不亂的頭發(fā)上搞挣,一...
    開(kāi)封第一講書(shū)人閱讀 51,698評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音音羞,去河邊找鬼囱桨。 笑死,一個(gè)胖子當(dāng)著我的面吹牛嗅绰,可吹牛的內(nèi)容都是我干的舍肠。 我是一名探鬼主播,決...
    沈念sama閱讀 40,418評(píng)論 3 419
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼窘面,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼翠语!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起财边,我...
    開(kāi)封第一講書(shū)人閱讀 39,332評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤肌括,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后酣难,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體谍夭,經(jīng)...
    沈念sama閱讀 45,796評(píng)論 1 316
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,968評(píng)論 3 337
  • 正文 我和宋清朗相戀三年鲸鹦,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了慧库。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,110評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡馋嗜,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出吵瞻,到底是詐尸還是另有隱情葛菇,我是刑警寧澤,帶...
    沈念sama閱讀 35,792評(píng)論 5 346
  • 正文 年R本政府宣布橡羞,位于F島的核電站眯停,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏卿泽。R本人自食惡果不足惜莺债,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,455評(píng)論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望签夭。 院中可真熱鬧齐邦,春花似錦、人聲如沸第租。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,003評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)慎宾。三九已至丐吓,卻和暖如春浅悉,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背券犁。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,130評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工术健, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人粘衬。 一個(gè)月前我還...
    沈念sama閱讀 48,348評(píng)論 3 373
  • 正文 我出身青樓荞估,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親色难。 傳聞我的和親對(duì)象是個(gè)殘疾皇子泼舱,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,047評(píng)論 2 355

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

  • 你在使用 Retrofit 的時(shí)候,是否會(huì)有如下幾點(diǎn)疑惑枷莉? 什么是動(dòng)態(tài)代理娇昙? 整個(gè)請(qǐng)求的流程是怎樣的? 底層是如何...
    笨笨11閱讀 685評(píng)論 0 6
  • 一笤妙、前言二冒掌、源碼解析1、構(gòu)建Retrofit對(duì)象 1.1蹲盘、Retrofit類(lèi)的成員變量 1.2股毫、Retrofi...
    huangLearn閱讀 594評(píng)論 0 1
  • 一、Retrofit本質(zhì)流程和相關(guān)類(lèi) 1.具體過(guò)程處理如下 通過(guò)解析 網(wǎng)絡(luò)請(qǐng)求接口的注解 配置 網(wǎng)絡(luò)請(qǐng)求參數(shù) 通過(guò)...
    zzq_nene閱讀 387評(píng)論 0 1
  • Retrofit 是當(dāng)下android開(kāi)發(fā)最流行的網(wǎng)絡(luò)請(qǐng)求框架召衔。用了Retrofit體會(huì)到了它的強(qiáng)大之處一直對(duì)它的...
    telyo閱讀 250評(píng)論 0 1
  • Retrofit在代碼中的構(gòu)建方式 根據(jù)構(gòu)建方式铃诬,我們先來(lái)看一下Retrofit類(lèi)源碼 (1)Retrofit中的...
    dlihasa閱讀 332評(píng)論 0 4