Retrofit 2.6.2 源碼分析

Retrofit 2.6.2 源碼分析

原文鏈接
Retrofit 是對(duì)網(wǎng)絡(luò)請(qǐng)求接口的封裝,它內(nèi)部最終的網(wǎng)絡(luò)請(qǐng)求還是通過(guò) OkHttp 實(shí)現(xiàn)的,但是它使我們只需要編寫(xiě) java 接口就能創(chuàng)建 OkHttp 需要的請(qǐng)求。

基本使用

// 定義 get 請(qǐng)求接口
interface BaiDuApi {
    @GET("s")
    fun getBaiDu(): Call<ResponseBody>
}
        // 自定義 OkHttpClient
        val okHttpClient = OkHttpClient.Builder().eventListener(object : EventListener() {
            override fun callStart(call: Call) {
                super.callStart(call)
                Log.d("OkHttpClient", "callStart:${call.request()}")
            }

        }).build()
                // 初始化 Retrofit
        val retrofit = Retrofit.Builder()
            .baseUrl("https://www.baidu.com/")
            .client(okHttpClient)
            .build()

        val baiDuApi = retrofit.create(BaiDuApi::class.java)
        val retrofitCall = baiDuApi.getBaiDu()
        retrofitCall.enqueue(object : retrofit2.Callback<ResponseBody> {
            override fun onFailure(call: retrofit2.Call<ResponseBody>, t: Throwable) {
                Log.d("Retrofit", t.toString())
            }

            override fun onResponse(
                call: retrofit2.Call<ResponseBody>,
                response: retrofit2.Response<ResponseBody>
            ) {
                Log.d("Retrofit", response.toString())
            }
        })

因?yàn)閮?nèi)部是用 OkHttp 所有可以自己初始化一個(gè) OkHttpClient 對(duì)象這樣我們可以在攔截器里面實(shí)現(xiàn)很多自己需要的功能。

還是和上一篇一樣,我們從如何使用入手,這里主要涉及到 Retrofit、Call、Callback 幾個(gè)對(duì)象,因?yàn)?BaiDuApi 是我們自己創(chuàng)建的接口,但是實(shí)際使用的時(shí)候還是通過(guò)它的方法獲取了一個(gè) Call 對(duì)象,所以我們先看一下 Retrofit.create 方法里面到底做了什么。

一、Retrofit.create

    // Retrofit.java
    public <T> T create(final Class<T> service) {
    // 1、
    Utils.validateServiceInterface(service);
    // 5、
    if (validateEagerly) {
      eagerlyValidateMethods(service);
    }
    // 2、
    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 @Nullable Object invoke(Object proxy, Method method,
              @Nullable Object[] args) throws Throwable {
            // 3、
            if (method.getDeclaringClass() == Object.class) {
              return method.invoke(this, args);
            }
            if (platform.isDefaultMethod(method)) {
              return platform.invokeDefaultMethod(method, service, proxy, args);
            }
            // 4、
            return loadServiceMethod(method).invoke(args != null ? args : emptyArgs);
          }
        });
  }
  1. 接口的合法性驗(yàn)證。
  2. 可以看到 create 方法采用了動(dòng)態(tài)代理的方式代理了我們定義的接口的方法。
  3. Object 的方法就直接正常調(diào)用,以及一些默認(rèn)方法的處理。
  4. 通過(guò) loadServiceMethod 處理再執(zhí)行(看過(guò)低版本的人可能會(huì)發(fā)現(xiàn) create 和之前稍微有點(diǎn)不一樣,但是事實(shí)上只是調(diào)用的位置有所調(diào)整而已,而且這個(gè)版本還對(duì) Kotlin 協(xié)程做了支持)。注意這個(gè) invoke 方法。
  5. 再回過(guò)頭看來(lái) eagerlyValidateMethods,其實(shí)這里只是采用餓漢的形式,預(yù)先遍歷了接口的符合要求的方法做 loadServiceMethod 處理。

二、loadServiceMethod

這個(gè)方法是將我們定義的接口方法,通過(guò)注解解析為一個(gè) ServiceMethod 對(duì)象,是核心部分。

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

    synchronized (serviceMethodCache) {
      result = serviceMethodCache.get(method);
      if (result == null) {
        // 2、
        result = ServiceMethod.parseAnnotations(this, method);
        serviceMethodCache.put(method, result);
      }
    }
    return result;
  }
  1. 可以看到這里用了一個(gè) Map 保存了 ServiceMethod 對(duì)象,method 為 key。
  2. 如果前面沒(méi)有取到則通過(guò) ServiceMethod.parseAnnotations 解析創(chuàng)建一個(gè),然后放到 Map 中。
  // ServiceMethod.java
  static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) {
    // 3、
    RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method);
        // 4、
    Type returnType = method.getGenericReturnType();
    if (Utils.hasUnresolvableType(returnType)) {
      throw methodError(method,
          "Method return type must not include a type variable or wildcard: %s", returnType);
    }
    if (returnType == void.class) {
      throw methodError(method, "Service methods cannot return void.");
    }
        // 5、
    return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);
  }
  1. 調(diào)用 RequestFactory.parseAnnotations 方法解析請(qǐng)求接口,返回 RequestFactory 為之后構(gòu)造 OkHttp 的 Request 做準(zhǔn)備。
  2. 對(duì)接口方法的返回值做非法的判斷,如果非法直接拋出異常。
  3. 創(chuàng)建 HttpServiceMethod 對(duì)象,這個(gè)后面會(huì)講到。

三、RequestFactory.parseAnnotations

對(duì)應(yīng)第二節(jié)步驟 3 的解析處理。

  // RequestFactory.java
  static RequestFactory parseAnnotations(Retrofit retrofit, Method method) {
    return new Builder(retrofit, method).build();
  }
        // Builder.build()
    RequestFactory build() {
      // 1、
      for (Annotation annotation : methodAnnotations) {
        parseMethodAnnotation(annotation);
      }
            // 2、沒(méi)有具體的請(qǐng)求類(lèi)型
      if (httpMethod == null) {
        throw methodError(method, "HTTP method annotation is required (e.g., @GET, @POST, etc.).");
      }

      if (!hasBody) {
        // isMultipart 但是卻沒(méi)有請(qǐng)求體
        if (isMultipart) {
          throw methodError(method,
              "Multipart can only be specified on HTTP methods with request body (e.g., @POST).");
        }
        // isFormEncoded 但是卻沒(méi)有請(qǐng)求體
        if (isFormEncoded) {
          throw methodError(method, "FormUrlEncoded can only be specified on HTTP methods with "
              + "request body (e.g., @POST).");
        }
      }
            // 3、
      int parameterCount = parameterAnnotationsArray.length;
      parameterHandlers = new ParameterHandler<?>[parameterCount];
      for (int p = 0, lastParameter = parameterCount - 1; p < parameterCount; p++) {
        parameterHandlers[p] =
            parseParameter(p, parameterTypes[p], parameterAnnotationsArray[p], p == lastParameter);
      }
            // 4、
      if (relativeUrl == null && !gotUrl) {
        throw methodError(method, "Missing either @%s URL or @Url parameter.", httpMethod);
      }
      if (!isFormEncoded && !isMultipart && !hasBody && gotBody) {
        throw methodError(method, "Non-body HTTP method cannot contain @Body.");
      }
      if (isFormEncoded && !gotField) {
        throw methodError(method, "Form-encoded method must contain at least one @Field.");
      }
      if (isMultipart && !gotPart) {
        throw methodError(method, "Multipart method must contain at least one @Part.");
      }
            // 5、
      return new RequestFactory(this);
    }

  1. 遍歷方法上的注解,并解析,主要是解析方法對(duì)應(yīng) Http 請(qǐng)求的方法(GET、POST 之類(lèi)的)以及首部字段。可以從下邊的代碼看的,請(qǐng)求的類(lèi)型都是注解,而與之對(duì)應(yīng)的參數(shù)都是通過(guò)正則匹配解析。
    private void parseMethodAnnotation(Annotation annotation) {
      // PATCH、POST、PUT 類(lèi)型的請(qǐng)求有請(qǐng)求體,其余的沒(méi)有
      if (annotation instanceof DELETE) {
        parseHttpMethodAndPath("DELETE", ((DELETE) annotation).value(), false);
      } else if (annotation instanceof GET) {
        parseHttpMethodAndPath("GET", ((GET) annotation).value(), false);
      } else if (annotation instanceof HEAD) {
        parseHttpMethodAndPath("HEAD", ((HEAD) annotation).value(), false);
      } else if (annotation instanceof PATCH) {
        parseHttpMethodAndPath("PATCH", ((PATCH) annotation).value(), true);
      } else if (annotation instanceof POST) {
        parseHttpMethodAndPath("POST", ((POST) annotation).value(), true);
      } else if (annotation instanceof PUT) {
        parseHttpMethodAndPath("PUT", ((PUT) annotation).value(), true);
      } else if (annotation instanceof OPTIONS) {
        parseHttpMethodAndPath("OPTIONS", ((OPTIONS) annotation).value(), false);
      } else if (annotation instanceof HTTP) {
        HTTP http = (HTTP) annotation;
        parseHttpMethodAndPath(http.method(), http.path(), http.hasBody());
      } else if (annotation instanceof retrofit2.http.Headers) {
        String[] headersToParse = ((retrofit2.http.Headers) annotation).value();
        if (headersToParse.length == 0) {
          throw methodError(method, "@Headers annotation is empty.");
        }
        // 解析首部字段
        headers = parseHeaders(headersToParse);
      } else if (annotation instanceof Multipart) {
        if (isFormEncoded) {
          throw methodError(method, "Only one encoding annotation is allowed.");
        }
        isMultipart = true;
      } else if (annotation instanceof FormUrlEncoded) {
        if (isMultipart) {
          throw methodError(method, "Only one encoding annotation is allowed.");
        }
        isFormEncoded = true;
      }
    }
    private void parseHttpMethodAndPath(String httpMethod, String value, boolean hasBody) {
      if (this.httpMethod != null) {
        throw methodError(method, "Only one HTTP method is allowed. Found: %s and %s.",
            this.httpMethod, httpMethod);
      }
      // 記錄請(qǐng)求的方法,是否有請(qǐng)求體
      this.httpMethod = httpMethod;
      this.hasBody = hasBody;

      if (value.isEmpty()) {
        return;
      }

      // 解析 path 信息,以及參數(shù) 
      int question = value.indexOf('?');
      if (question != -1 && question < value.length() - 1) {
        // Ensure the query string does not have any named parameters.
        String queryParams = value.substring(question + 1);
        Matcher queryParamMatcher = PARAM_URL_REGEX.matcher(queryParams);
        if (queryParamMatcher.find()) {
          throw methodError(method, "URL query string \"%s\" must not have replace block. "
              + "For dynamic query parameters use @Query.", queryParams);
        }
      }

      this.relativeUrl = value;
      this.relativeUrlParamNames = parsePathParameters(value);
    }
  1. 不合法情況的檢查,基本上就是定義接口不符合規(guī)泛造成的前后矛盾的情況。

  2. 遍歷請(qǐng)求接口方法的參數(shù)上的注解,并解析成為 ParameterHandler 保存在一個(gè)數(shù)組中。

    解析的方法為 parseParameter(p, parameterTypes[p], parameterAnnotationsArray[p], p == lastParameter) 它的幾個(gè)參數(shù)分別是參數(shù)的索引、參數(shù)的類(lèi)型、參數(shù)的注解、是否可能是 Kotlin 的 suspend 方法,因?yàn)樵?Kotlin 編譯的時(shí)候針對(duì) suspend 方法會(huì)給它添加一個(gè)為 Continuation 類(lèi)型的參數(shù),所以這里在解析最后一個(gè)參數(shù)的時(shí)候可能會(huì)對(duì)參數(shù)類(lèi)型進(jìn)行判斷,如果為 Continuation 則表明這個(gè)接口方法是 suspend 的,然后會(huì)用 isKotlinSuspendFunction = true 做標(biāo)記。

    解析為 ParameterHandler 的代碼比較多這里就不粘貼代碼了,而且它的具體實(shí)現(xiàn)也有很多,但是最終使用的時(shí)候都會(huì)調(diào)用它們的 apply 方法,并且傳入 retrofit2.RequestBuilder 對(duì)象,以及該 ParameterHandler 對(duì)應(yīng)的參數(shù),然后不同類(lèi)型的 ParameterHandler 會(huì)調(diào)用 retrofit2.RequestBuilder 做不同的處理來(lái)構(gòu)建請(qǐng)求。

  3. 又是不合法情況的檢查。

  4. 返回 RequestFactory 對(duì)象到第二節(jié)步驟 3。

四、HttpServiceMethod.parseAnnotations

對(duì)應(yīng)第二節(jié)步驟 5 的解析處理。這里包含了 Retrofit 兩個(gè)很重要的操作:

  • 創(chuàng)建適配器可以把 OkHttpCall 適配為我們最初 api 接口定義的方法的返回值。
  • 創(chuàng)建轉(zhuǎn)換器可以把 ResponseBody 轉(zhuǎn)換為我們最終希望回調(diào)里面的參數(shù)類(lèi)型的轉(zhuǎn)換器。
  // HttpServiceMethod.java
  static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations(
      Retrofit retrofit, Method method, RequestFactory requestFactory) {
    // 第三節(jié)步驟 3 提到的 suspend 方法的標(biāo)記
    boolean isKotlinSuspendFunction = requestFactory.isKotlinSuspendFunction;
    boolean continuationWantsResponse = false;
    boolean continuationBodyNullable = false;

    Annotation[] annotations = method.getAnnotations();
    Type adapterType;
    if (isKotlinSuspendFunction) {
      // 1、
      Type[] parameterTypes = method.getGenericParameterTypes();
      Type responseType = Utils.getParameterLowerBound(0,
          (ParameterizedType) parameterTypes[parameterTypes.length - 1]);
      if (getRawType(responseType) == Response.class && responseType instanceof ParameterizedType) {
        // Unwrap the actual body type from Response<T>.
        responseType = Utils.getParameterUpperBound(0, (ParameterizedType) responseType);
        continuationWantsResponse = true;
      } else {
        // TODO figure out if type is nullable or not
        // Metadata metadata = method.getDeclaringClass().getAnnotation(Metadata.class)
        // Find the entry for method
        // Determine if return type is nullable or not
      }
            // 2、
      adapterType = new Utils.ParameterizedTypeImpl(null, Call.class, responseType);
      annotations = SkipCallbackExecutorImpl.ensurePresent(annotations);
    } else {
      // 3、
      adapterType = method.getGenericReturnType();
    }
        // 4、
    CallAdapter<ResponseT, ReturnT> callAdapter =
        createCallAdapter(retrofit, method, adapterType, annotations);
    Type responseType = callAdapter.responseType();
    // 5、
    if (responseType == okhttp3.Response.class) {
      throw methodError(method, "'"
          + getRawType(responseType).getName()
          + "' is not a valid response body type. Did you mean ResponseBody?");
    }
    if (responseType == Response.class) {
      throw methodError(method, "Response must include generic type (e.g., Response<String>)");
    }
    // TODO support Unit for Kotlin?
    if (requestFactory.httpMethod.equals("HEAD") && !Void.class.equals(responseType)) {
      throw methodError(method, "HEAD method must use Void as response type.");
    }
        // 6、
    Converter<ResponseBody, ResponseT> responseConverter =
        createResponseConverter(retrofit, method, responseType);

    okhttp3.Call.Factory callFactory = retrofit.callFactory;
    // 7、
    if (!isKotlinSuspendFunction) {
      return new CallAdapted<>(requestFactory, callFactory, responseConverter, callAdapter);
    } else if (continuationWantsResponse) {
      //noinspection unchecked Kotlin compiler guarantees ReturnT to be Object.
      return (HttpServiceMethod<ResponseT, ReturnT>) new SuspendForResponse<>(requestFactory,
          callFactory, responseConverter, (CallAdapter<ResponseT, Call<ResponseT>>) callAdapter);
    } else {
      //noinspection unchecked Kotlin compiler guarantees ReturnT to be Object.
      return (HttpServiceMethod<ResponseT, ReturnT>) new SuspendForBody<>(requestFactory,
          callFactory, responseConverter, (CallAdapter<ResponseT, Call<ResponseT>>) callAdapter,
          continuationBodyNullable);
    }
  }
  1. 如果是 Kotlin 的 suspend 方法,那么就獲取最后一個(gè)參數(shù)的泛型的下界通配類(lèi)型(Continuation 對(duì)象的泛型),即原 suspend 方法的返回值類(lèi)型。如果這個(gè)類(lèi)型是個(gè) retrofit2.Response 類(lèi)型或者帶泛型的類(lèi)型的話,進(jìn)一步獲取泛型的類(lèi)型。舉個(gè)例子:

    suspend fun getResponse():Response<ResponseBody> 那么最終 responseType = ResponseBody.class,然后標(biāo)記 continuationWantsResponse = true。

  2. 用步驟 1 獲取的類(lèi)型創(chuàng)建 retrofit2.Call<T> 賦值給 adapterType。給方法的注解插入一個(gè) SkipCallbackExecutor 注解,用于跳過(guò) callbackExecutor 的調(diào)度(目前不清楚,后面繼續(xù)關(guān)注)。

    如果沒(méi)有了解過(guò) Kotlin 和協(xié)程的話,不用在意步驟 1 和 2也沒(méi)關(guān)系,等了解了再回來(lái)看。

  3. 如果不是 Kotlin 的 suspend 方法,那么很簡(jiǎn)單直接獲取返回值的類(lèi)型。

  4. 創(chuàng)建一個(gè) CallAdapter 對(duì)象,這個(gè)對(duì)象是用來(lái)把 OkHttpCall 適配為我們定義的方法的返回值類(lèi)型的,這里我們看下拿到的對(duì)象的實(shí)現(xiàn)是什么。

  // HttpServiceMethod.java
  private static <ResponseT, ReturnT> CallAdapter<ResponseT, ReturnT> createCallAdapter(
      Retrofit retrofit, Method method, Type returnType, Annotation[] annotations) {
            // 直接調(diào)用 Retrofit 的方法,并進(jìn)一步調(diào)用到 nextCallAdapter
      return (CallAdapter<ResponseT, ReturnT>) retrofit.callAdapter(returnType, annotations);
    //省略異常處理
  }
  // Retrofit.java
  public CallAdapter<?, ?> nextCallAdapter(@Nullable CallAdapter.Factory skipPast, Type returnType,
      Annotation[] annotations) {
        // 省略一些代碼
    int start = callAdapterFactories.indexOf(skipPast) + 1;
    // 通過(guò) callAdapterFactories 查找,那么我們看下這個(gè)列表是什么時(shí)候創(chuàng)建的
    for (int i = start, count = callAdapterFactories.size(); i < count; i++) {
      CallAdapter<?, ?> adapter = callAdapterFactories.get(i).get(returnType, annotations, this);
      if (adapter != null) {
        return adapter;
      }
    }
    // 省略一些代碼
  }
    // Retrofit.Builder 對(duì)象的 build()
    public Retrofit build() {
      // 省略一些代碼
      Executor callbackExecutor = this.callbackExecutor;
      if (callbackExecutor == null) {
        // 如果沒(méi)定義,獲取默認(rèn)的執(zhí)行器
        callbackExecutor = platform.defaultCallbackExecutor();
      }
      // 找到了,除了我們?cè)诔跏蓟约旱?Retrofit 對(duì)象的時(shí)候自己可以添加進(jìn)來(lái)
      List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(this.callAdapterFactories);
      // 還有就是和平臺(tái)相關(guān)的默認(rèn)添加的
      callAdapterFactories.addAll(platform.defaultCallAdapterFactories(callbackExecutor));

      //省略一些代碼
    }
  // Platform.java 
  static class Android extends Platform {
    // 省略一些代碼
    @Override public Executor defaultCallbackExecutor() {
      return new MainThreadExecutor();
    }

    @Override List<? extends CallAdapter.Factory> defaultCallAdapterFactories(
        @Nullable Executor callbackExecutor) {
      if (callbackExecutor == null) throw new AssertionError();
      // 因?yàn)槲以?Android 使用所以直接找 Android 平臺(tái),
      // 這里根據(jù)目標(biāo)版本的不同,會(huì)有點(diǎn)不一樣,但是至少會(huì)有一個(gè) DefaultCallAdapterFactory
      // Android api 24 對(duì)應(yīng) Android 7.0 
      // 但是一般我們開(kāi)發(fā)應(yīng)用會(huì)兼容到 4.0 左右,所以就先忽略 CompletableFutureCallAdapterFactory 了
      DefaultCallAdapterFactory executorFactory = new DefaultCallAdapterFactory(callbackExecutor);
      return Build.VERSION.SDK_INT >= 24
        ? asList(CompletableFutureCallAdapterFactory.INSTANCE, executorFactory)
        : singletonList(executorFactory);
    }
    // 省略一些代碼
        // 留意一下這個(gè) Executor,僅僅是使用 handler post 到主線程,就是我們 build 方法中執(zhí)行器的實(shí)現(xiàn)
    static class MainThreadExecutor implements Executor {
      private final Handler handler = new Handler(Looper.getMainLooper());
      @Override public void execute(Runnable r) {
        handler.post(r);
      }
    }
  }

好了,現(xiàn)在我們終于定位到了創(chuàng)建 CallAdapter 對(duì)象的工廠類(lèi)了 DefaultCallAdapterFactory,馬上來(lái)看一下獲取的具體實(shí)現(xiàn)。

  // DefaultCallAdapterFactory.java
  @Override public @Nullable CallAdapter<?, ?> get(
      Type returnType, Annotation[] annotations, Retrofit retrofit) {
    // 省略合法性驗(yàn)證代碼
    // 獲取泛型上的類(lèi)型
    final Type responseType = Utils.getParameterUpperBound(0, (ParameterizedType) returnType);
    // 還記得我們步驟 2 中對(duì) Kotlin suspend 方法插入的 SkipCallbackExecutor 注解嘛?生效了
    // 協(xié)程會(huì)自己調(diào)度,所以就不需要我們的調(diào)度器了
    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) {
        // 如果不是協(xié)程,我們還是需要調(diào)度器來(lái)為我們切換線程的,畢竟 OkHttp 的回調(diào)不在主線程
        return executor == null
            ? call
            : new ExecutorCallbackCall<>(executor, call);
      }
    };
  }

我們終于找到了 CallAdapter 的實(shí)現(xiàn),但是現(xiàn)在還沒(méi)有到它發(fā)揮作用的時(shí)候,真正使用的時(shí)候我們會(huì)調(diào)用它的 adapt 方法,根據(jù)實(shí)際的情況會(huì)直接返回入?yún)?call,或者進(jìn)一步分裝成 ExecutorCallbackCall 這個(gè)我們后面會(huì)介紹到。

ps:看過(guò)以前版本 Retrofit 的同學(xué)可能還會(huì)發(fā)現(xiàn)這個(gè) DefaultCallAdapterFactory 是以前版本的 DefaultCallAdapterFactory 和 ExecutorCallAdapterFactory 的合體。

  1. 對(duì)獲取的 CallAdapter.responseType() 合法性的驗(yàn)證。
  2. 創(chuàng)建一個(gè) Converter 對(duì)象,用于把 ResponseBody 轉(zhuǎn)換為我們最終希望回調(diào)里面的參數(shù)類(lèi)型,根據(jù)文章一開(kāi)始的例子,我們會(huì)得到 BufferingResponseBodyConverter 對(duì)象(見(jiàn) BuiltInConverters.java),下邊看實(shí)現(xiàn)。
// HttpServiceMethod.java
  private static <ResponseT> Converter<ResponseBody, ResponseT> createResponseConverter(
      Retrofit retrofit, Method method, Type responseType) {
    Annotation[] annotations = method.getAnnotations();
        // 直接調(diào)用 Retrofit 的方法,并進(jìn)一步調(diào)用到 nextResponseBodyConverter
        // 過(guò)程和 CallAdapter 類(lèi)似,直接看 Retrofit.Builder 的 build 方法
      return retrofit.responseBodyConverter(responseType, annotations);
    //省略異常處理
  }
    // Retrofit.Builder 對(duì)象的 build(),省略很多不相關(guān)的代碼
    public Retrofit build() {
      List<Converter.Factory> converterFactories = new ArrayList<>(
          1 + this.converterFactories.size() + platform.defaultConverterFactoriesSize());

      // 首先添加內(nèi)置轉(zhuǎn)換器工廠,里面實(shí)現(xiàn)了多個(gè)轉(zhuǎn)換器包括把字節(jié)流轉(zhuǎn)換成 ResponseBody,
      // ResponseBody 轉(zhuǎn)換為 java 中的 Void 或者 Kotlin 中的 Unit 時(shí)關(guān)閉流的操作等
      converterFactories.add(new BuiltInConverters());
      // 有自定義的添加自定義,
      // 我們常用的 GsonConverterFactory 就是把 json 字符串轉(zhuǎn)換為具體對(duì)象,
      // 或者把對(duì)象轉(zhuǎn)換成 json 字符串
      converterFactories.addAll(this.converterFactories);
      // 平臺(tái)默認(rèn)的轉(zhuǎn)換器工廠,下邊看一下 Android 平臺(tái)里面的默認(rèn)實(shí)現(xiàn)
      converterFactories.addAll(platform.defaultConverterFactories());

      return new Retrofit(callFactory, baseUrl, unmodifiableList(converterFactories),
          unmodifiableList(callAdapterFactories), callbackExecutor, validateEagerly);
    }
  // Platform.java 省略不相關(guān)的代碼
  static class Android extends Platform {

    @Override List<? extends Converter.Factory> defaultConverterFactories() {
      // 好吧,低版本的就直接沒(méi)有,如果感興趣的可以看下 GsonConverterFactory 
      return Build.VERSION.SDK_INT >= 24
          ? singletonList(OptionalConverterFactory.INSTANCE)
          : Collections.<Converter.Factory>emptyList();
    }
  }
  1. 把之前獲得的幾個(gè)對(duì)象保存在 HttpServiceMethod 的子類(lèi)中后返回到動(dòng)態(tài)代理調(diào)用方法時(shí)候調(diào)用 loadServiceMethod(Method method)的地方,見(jiàn)第一節(jié)步驟 4。

    HttpServiceMethod 的子類(lèi)有三個(gè),其中兩個(gè)是為 Kotlin suspend 方法準(zhǔn)備的,可以看到 Retrofit 為了協(xié)程做了很多工作,我會(huì)以介紹非協(xié)程為主,但是還是會(huì)講到協(xié)程請(qǐng)況下的處理。沒(méi)有接觸過(guò)協(xié)程的也不用糾結(jié)直接略過(guò),等啥時(shí)候了解了再來(lái)回味一下。

五、HttpServiceMethod.invoke

回到第一節(jié)步驟 4,拿到 HttpServiceMethod 對(duì)象之后我們調(diào)用了它 invoke 方法,把參數(shù)傳遞進(jìn)去。

即我們基本使用例子里調(diào)用 baiDuApi.getBaiDu() 就會(huì)觸發(fā):

// Retrofit.java create 方法返回的動(dòng)態(tài)代理中
return loadServiceMethod(method).invoke(args != null ? args : emptyArgs);

  // invoke 是 ServiceMethod 的方法,具體實(shí)現(xiàn)在 HttpServiceMethod 中
  // HttpServiceMethod.java
  @Override final @Nullable ReturnT invoke(Object[] args) {
    // 創(chuàng)建了第四節(jié)開(kāi)始提到的 OkHttpCall 對(duì)象,緊接著調(diào)用自己的抽象 adapt 方法
    // 1、
    Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);
    return adapt(call, args);
  }
  protected abstract @Nullable ReturnT adapt(Call<ResponseT> call, Object[] args);
  1. HttpServiceMethod.invoke 方法中創(chuàng)建了 OkHttpCall 對(duì)象,這個(gè)對(duì)象實(shí)現(xiàn)了 retrofit2.Call 接口,里面是封裝了使用 OkHttp 發(fā)請(qǐng)求的邏輯。之后又調(diào)用了自己的抽象方法 adapt,具體實(shí)現(xiàn)在子類(lèi)中。

    前面提到 HttpServiceMethod 的子類(lèi)有三個(gè):CallAdapted,SuspendForResponse,SuspendForBody,看類(lèi)名稱(chēng)也可以猜想到后兩個(gè)方法是對(duì) Kotlin suspend 方法的支持。

    這里主要講一下 CallAdapted 類(lèi)。

  // HttpServiceMethod.java
  static final class CallAdapted<ResponseT, ReturnT> extends HttpServiceMethod<ResponseT, ReturnT> {
    private final CallAdapter<ResponseT, ReturnT> callAdapter;
        // requestFactory 為第二節(jié)步驟 3 拿到的 RequestFactory 對(duì)象,用于構(gòu)建 OkHttp 請(qǐng)求
    // callFactory 為 OkHttpClient 對(duì)象
    // responseConverter 為第四節(jié)步驟 6 拿到的轉(zhuǎn)換器對(duì)象,根據(jù)本文基礎(chǔ)使用的例子為
    // BufferingResponseBodyConverter
    // callAdapter 為第四節(jié)步驟 4 中 DefaultCallAdapterFactory.java 創(chuàng)建的對(duì)象
    CallAdapted(RequestFactory requestFactory, okhttp3.Call.Factory callFactory,
        Converter<ResponseBody, ResponseT> responseConverter,
        CallAdapter<ResponseT, ReturnT> callAdapter) {
      super(requestFactory, callFactory, responseConverter);
      this.callAdapter = callAdapter;
    }
        // 2、
    @Override protected ReturnT adapt(Call<ResponseT> call, Object[] args) {
      return callAdapter.adapt(call);
    }
  }
  1. 步驟 1會(huì)調(diào)用到 CallAdapted.adapter,這里在注釋中解釋了一下 CallAdapted 構(gòu)造方法里面的幾個(gè)參數(shù)便于理解,實(shí)際處理還得看 DefaultCallAdapterFactory 創(chuàng)建的 CallAdapter 見(jiàn)下。
    // DefaultCallAdapterFactory.java
    new CallAdapter<Object, Call<?>>() {
      @Override public Type responseType() {
        return responseType;
      }

      @Override public Call<Object> adapt(Call<Object> call) {
        // 如果不是協(xié)程,我們還是需要調(diào)度器來(lái)為我們切換線程的,畢竟 OkHttp 的回調(diào)不在主線程
        return executor == null
            ? call // 3、
            : new ExecutorCallbackCall<>(executor, call);
      }
    };

3、 這里我們會(huì)獲取到 ExecutorCallbackCall 對(duì)象,它的參數(shù)分別為把方法放到主線程的 MainThreadExecutor(第四節(jié)步驟 4 中提到過(guò))、OkHttpCall。

六、開(kāi)始調(diào)用請(qǐng)求

                // 開(kāi)始的例子
                // 1、
        val retrofitCall = baiDuApi.getBaiDu()
        retrofitCall.enqueue(object : retrofit2.Callback<ResponseBody> {
            override fun onFailure(call: retrofit2.Call<ResponseBody>, t: Throwable) {
                Log.d("Retrofit", t.toString())
            }

            override fun onResponse(
                call: retrofit2.Call<ResponseBody>,
                response: retrofit2.Response<ResponseBody>
            ) {
                Log.d("Retrofit", response.toString())
            }
        })
  1. retrofitCall 就是 ExecutorCallbackCall 對(duì)象,調(diào)用它的 enqueue 方法,傳入我們的監(jiān)聽(tīng) Callback 。
  // DefaultCallAdapterFactory.java
    // 省略了部分代碼
  static final class ExecutorCallbackCall<T> implements Call<T> {
    final Executor callbackExecutor;
    final Call<T> delegate;
    ExecutorCallbackCall(Executor callbackExecutor, Call<T> delegate) {
      this.callbackExecutor = callbackExecutor;
      this.delegate = delegate;
    }
    @Override public void enqueue(final Callback<T> callback) {
      checkNotNull(callback, "callback == null");
            // 2、
      delegate.enqueue(new Callback<T>() {
        @Override public void onResponse(Call<T> call, final Response<T> response) {
          callbackExecutor.execute(new Runnable() {
            @Override public void run() {
              if (delegate.isCanceled()) {
                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(new Runnable() {
            @Override public void run() {
              callback.onFailure(ExecutorCallbackCall.this, t);
            }
          });
        }
      }); 
    }
  1. delegate 是 OkHttpCall 對(duì)象,使用過(guò) OkHttp 的應(yīng)該知道它的 enqueue 是執(zhí)行在子線程的,所以 ExecutorCallbackCall 為我們做的就是把在子線程的回調(diào)中,通過(guò) MainThreadExecutor 在主線程中調(diào)用 retrofit2.Callback 的回調(diào)。當(dāng)然這個(gè) enqueue 還不是真正的 OkHttp 的 enqueue,它做了封裝。
  // OkHttpCall.java     // 太長(zhǎng)了,刪除部分代碼
  @Override public void enqueue(final Callback<T> callback) {
    synchronized (this) {
      if (executed) throw new IllegalStateException("Already executed.");
      executed = true;
      if (call == null && failure == null) {
          // 3、
          call = rawCall = createRawCall();
      }
    }
    // 4、
    call.enqueue(new okhttp3.Callback() {
      @Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse) {
        Response<T> response;
            // 5、
          response = parseResponse(rawResponse);
            // 6、
          callback.onResponse(OkHttpCall.this, response);
      }

      @Override public void onFailure(okhttp3.Call call, IOException e) {
        callFailure(e);
      }
      private void callFailure(Throwable e) {
          callback.onFailure(OkHttpCall.this, e);
      }
    });
  }
  private okhttp3.Call createRawCall() throws IOException {
    okhttp3.Call call = callFactory.newCall(requestFactory.create(args));
    if (call == null) {
      throw new NullPointerException("Call.Factory returned null.");
    }
    return call;
  }
  1. 創(chuàng)建 OkHttp 的請(qǐng)求的 okhttp3.Call 對(duì)象,調(diào)用了 requestFactory.create(args) 構(gòu)造 Request 對(duì)象。
  okhttp3.Request create(Object[] args) throws IOException {
    // 這個(gè)數(shù)組見(jiàn)第三節(jié)步驟 3,里面保存了解析出來(lái)的參數(shù)的 key 等信息
    ParameterHandler<Object>[] handlers = (ParameterHandler<Object>[]) parameterHandlers;
    int argumentCount = args.length;
    RequestBuilder requestBuilder = new RequestBuilder(httpMethod, baseUrl, relativeUrl,
        headers, contentType, hasBody, isFormEncoded, isMultipart);

    if (isKotlinSuspendFunction) {
            // 如果是 suspend 方法,那么就需要少處理一個(gè),因?yàn)樽詈笠粋€(gè)是 Continuation
      argumentCount--;
    }

    List<Object> argumentList = new ArrayList<>(argumentCount);
    for (int p = 0; p < argumentCount; p++) {
      argumentList.add(args[p]);
      // 調(diào)用 ParameterHandler.apply 往 requestBuilder 里面設(shè)置參數(shù)
      handlers[p].apply(requestBuilder, args[p]);
    }

    return requestBuilder.get()
        .tag(Invocation.class, new Invocation(method, argumentList))
        .build();
  }
  1. 發(fā)起真正的 OkHttp 異步請(qǐng)求。
  2. 解析響應(yīng)。
  Response<T> parseResponse(okhttp3.Response rawResponse) throws IOException {
    // 分離響應(yīng)體和響應(yīng)頭,使得它們可以單獨(dú)傳輸處理
    ResponseBody rawBody = rawResponse.body();
    rawResponse = rawResponse.newBuilder()
        .body(new NoContentResponseBody(rawBody.contentType(), rawBody.contentLength()))
        .build();

    int code = rawResponse.code();
    if (code < 200 || code >= 300) {
        // 請(qǐng)求狀態(tài)異常的響應(yīng)
        ResponseBody bufferedBody = Utils.buffer(rawBody);
        return Response.error(bufferedBody, rawResponse);
    }

    if (code == 204 || code == 205) {
      rawBody.close();
      // 204 和 205 只需要傳送響應(yīng)頭
      return Response.success(null, rawResponse);
    }

    ExceptionCatchingResponseBody catchingBody = new ExceptionCatchingResponseBody(rawBody);
        // 調(diào)用轉(zhuǎn)換器將 ExceptionCatchingResponseBody 轉(zhuǎn)換成我們需要的數(shù)據(jù)對(duì)象
        // 有興趣可以看下我們前面提到的 BufferingResponseBodyConverter
      T body = responseConverter.convert(catchingBody);
      return Response.success(body, rawResponse);
  }
  1. 回調(diào)操作,這里還是在子線程,通過(guò) ExecutorCallbackCall 里面的流程,調(diào)用到主線程,到這里我們就真正的走過(guò)了一次 Retrofit 從 create 創(chuàng)建 Call 到發(fā)送請(qǐng)求,然后到回調(diào)主線程的操作了。

七、HttpServiceMethod 的子類(lèi)

HttpServiceMethod 繼承自 ServiceMethod 是 retrofit 中非常重要的對(duì)象,由我們定義的 Api 方法解析而來(lái)。

前面提到它有三個(gè)子類(lèi),第一個(gè) CallAdapted 我們剛才已經(jīng)講到過(guò)了,那么現(xiàn)在看看另外兩個(gè)的實(shí)現(xiàn),以及使用場(chǎng)景。

回顧第四節(jié)步驟 1 的解釋?zhuān)ùa就不再粘貼了,比較多):

如果是 Kotlin 的 suspend 方法,那么就獲取最后一個(gè)參數(shù)的泛型的下界通配類(lèi)型(Continuation 對(duì)象的泛型),即原 suspend 方法的返回值類(lèi)型。如果這個(gè)類(lèi)型是個(gè) retrofit2.Response 類(lèi)型或者帶泛型的類(lèi)型的話,進(jìn)一步獲取泛型的類(lèi)型。舉個(gè)例子:

suspend fun getResponse():Response<ResponseBody> 那么最終 responseType = ResponseBody.class,然后標(biāo)記 continuationWantsResponse = true。

第四節(jié)步驟 2 的解釋?zhuān)?/p>

用步驟 1 獲取的類(lèi)型創(chuàng)建 retrofit2.Call<T> 賦值給 adapterType。給方法的注解插入一個(gè) SkipCallbackExecutor 注解,用于跳過(guò) callbackExecutor 的調(diào)度

第四節(jié)步驟 4 中獲取 CallAdapter 對(duì)象時(shí),DefaultCallAdapterFactory 又對(duì)插入的 SkipCallbackExecutor 做處理:

 final Executor executor = Utils.isAnnotationPresent(annotations, SkipCallbackExecutor.class)
     ? null
     : callbackExecutor;

下面為 DefaultCallAdapterFactory 返回的 CallAdapter:

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

      @Override public Call<Object> adapt(Call<Object> call) {
        // 因?yàn)?executor == null,相當(dāng)于 adapt 方法啥也沒(méi)做轉(zhuǎn)接了一下
        return executor == null
            ? call
            : new ExecutorCallbackCall<>(executor, call);
      }
    };

綜上如果不是 suspend 方法,OkHttpCall 會(huì)被 ExecutorCallbackCall 包一層,然后再保存在 CallAdapted;否則再根據(jù) continuationWantsResponse 判斷,如果是 true 相當(dāng)于直接把 OkHttpCall 保存在 SuspendForResponse,如果 false 相當(dāng)于直接把 OkHttpCall 保存在 SuspendForBody。

如果 SuspendForResponse 對(duì)應(yīng) suspend fun getResponse():Response<ResponseBody>

那么 SuspendForBody 相當(dāng)于對(duì)應(yīng) suspend fun getResponse():ResponseBody

SuspendForResponse

  static final class SuspendForResponse<ResponseT> extends HttpServiceMethod<ResponseT, Object> {
    private final CallAdapter<ResponseT, Call<ResponseT>> callAdapter;
        // 省略構(gòu)造方法
    @Override protected Object adapt(Call<ResponseT> call, Object[] args) {
      // 這個(gè) call 就是 OkHttpCall
      call = callAdapter.adapt(call);
            // suspend 方法編譯時(shí)會(huì)給方法添加一個(gè)參數(shù) Continuation 它的泛型為原方法的返回值
      // Continuation 相當(dāng)于一個(gè)回調(diào)
      Continuation<Response<ResponseT>> continuation =
          (Continuation<Response<ResponseT>>) args[args.length - 1];

      try {
        // awaitResponse 是一個(gè) suspend 的拓展方法
        return KotlinExtensions.awaitResponse(call, continuation);
      } catch (Exception e) {
        return KotlinExtensions.yieldAndThrow(e, continuation);
      }
    }
  }
//KotlinExtensions.kt
suspend fun <T : Any> Call<T>.awaitResponse(): Response<T> {
  // suspendCancellableCoroutine 將異步操作封裝為掛起方法
  return suspendCancellableCoroutine { continuation ->
    continuation.invokeOnCancellation {
      cancel()
    }
        // 這個(gè)為 OkHttpCall.enqueue
    enqueue(object : Callback<T> {
      override fun onResponse(call: Call<T>, response: Response<T>) {
        // 調(diào)用回調(diào)
        continuation.resume(response)
      }

      override fun onFailure(call: Call<T>, t: Throwable) {
        continuation.resumeWithException(t)
      }
    })
  }
}

舉個(gè)直接用 suspend 請(qǐng)求的例子:

// @GET("s") suspend fun getResponse():Response<ResponseBody>
GlobalScope.launch(Dispatchers.Main){
  try{
    val response = baiDuApi.getResponse()
    //成功回調(diào)
    Log.d("Retrofit", "launch:$response")
    Log.d("Retrofit", "launch:${Thread.currentThread().name}")
  } catch (t : Throwable){
    //失敗回調(diào)
    Log.d("Retrofit", "launch:${t.message}")
  }
}

SuspendForBody

  static final class SuspendForBody<ResponseT> extends HttpServiceMethod<ResponseT, Object> {
    private final CallAdapter<ResponseT, Call<ResponseT>> callAdapter;
    // 構(gòu)造方法傳入,目前一直是 false,這個(gè)判斷還是一個(gè) todo,見(jiàn)第四節(jié)步驟 1 代碼
    private final boolean isNullable;
        // 省略構(gòu)造方法
    @Override protected Object adapt(Call<ResponseT> call, Object[] args) {
      // 這個(gè) call 就是 OkHttpCall
      call = callAdapter.adapt(call);

      Continuation<ResponseT> continuation = (Continuation<ResponseT>) args[args.length - 1];
      try {
        // awaitNullable,await 實(shí)現(xiàn)和上面的 awaitResponse 類(lèi)似,不再講
        return isNullable
            ? KotlinExtensions.awaitNullable(call, continuation)
            : KotlinExtensions.await(call, continuation);
      } catch (Exception e) {
        return KotlinExtensions.yieldAndThrow(e, continuation);
      }
    }
  }

結(jié)語(yǔ)

如果對(duì) OkHttp 的調(diào)用流程分析感興趣,可以看我之前的一篇文章《OkHttp 4.2.2 源碼分析》,版本 4.2.2 為是目前最新的,也是用 Kotlin 實(shí)現(xiàn)的。

Retrofit 使我們只需要編寫(xiě) java 接口就能創(chuàng)建 OkHttp 所需要的請(qǐng)求,以及后續(xù)開(kāi)源的 RxJava2CallAdapterFactory、GsonConverterFactory,讓我們也見(jiàn)識(shí)到了它設(shè)計(jì)上的強(qiáng)大。新版本的對(duì) suspend 方法的支持做了很多的工作,但是它的核心原理還是不變的。

其實(shí)閱讀源碼一個(gè)是看其中的原理,另一個(gè)是看在代碼還能怎么寫(xiě),順便思考一下日常開(kāi)發(fā)中是否能運(yùn)用起來(lái)。也希望這篇文章能引起一些沒(méi)有接觸過(guò) Kotlin 協(xié)程的同學(xué)對(duì)協(xié)程的興趣。

另外,喜歡的同學(xué),覺(jué)得對(duì)自己有幫助的同學(xué),務(wù)必請(qǐng)花一點(diǎn)點(diǎn)時(shí)間幫我點(diǎn)個(gè)贊!點(diǎn)贊之交淡如水,但這個(gè)很重要!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,367評(píng)論 6 532
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,001評(píng)論 3 413
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說(shuō)我怎么就攤上這事。” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 175,213評(píng)論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 62,535評(píng)論 1 308
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,317評(píng)論 6 405
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 54,868評(píng)論 1 321
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 42,963評(píng)論 3 440
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 42,090評(píng)論 0 285
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,599評(píng)論 1 331
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,549評(píng)論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 42,712評(píng)論 1 367
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,233評(píng)論 5 356
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 43,961評(píng)論 3 346
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 34,353評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 35,607評(píng)論 1 281
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,321評(píng)論 3 389
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 47,686評(píng)論 2 370