Retrofit2(2.4.0)

對okhttp3進(jìn)行封裝的網(wǎng)絡(luò)框架
github

1. 該框架用到的東西

該框架用了大量的注解
該框架依賴于okhttp3

2. 常用注解

1、@GET GET網(wǎng)絡(luò)請求方式
2、@POST POST網(wǎng)絡(luò)請求方式
3、@Headers() 頭信息參數(shù)
4、@Path() 路徑參數(shù),替換url地址中 { } 所括的部分
5、@Query() 查詢參數(shù),將在url地址中追加類似“page=1”的字符串,形成提交給服務(wù)端的請求參數(shù)
6、@QueryMap 查詢參數(shù)集合,將在url地址中追加類似
“type=text&username=abc&password=123”的字符串
7、@FormUrlEncoded 對表單域中填寫的內(nèi)容進(jìn)行編碼處理,避免亂碼
8、@Field() 指定form表單域中每個空間的額name以及相應(yīng)的數(shù)值
9、@FieldMap 表單域集合
10、@Multipart Post提交分塊請求,如果上傳文件,必須指定Multipart
11、@Body Post提交分塊請求
12、@Url 替換包含baseUrl的請求地址

3. 用法

假設(shè)有一個接口
http://www.wanandroid.com/banner/json

3.1創(chuàng)建一個retrofit實(shí)例
Retrofit retrofit= new Retrofit.Builder()
            .client(mClient)
            .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
            .addConverterFactory(GsonConverterFactory.create())
            .baseUrl(baseUrl)
            .build();

參數(shù)說明
mClient
OkHttpClient,配置參考OkHttp

RxJavaCallAdapterFactory.create()
將Call轉(zhuǎn)化為Observable

GsonConverterFactory.create()
將ResponseBody轉(zhuǎn)化為具體的gson解析對應(yīng)的實(shí)體類

baseUrl
接口的公共scheme
如上述接口,可以抽象為http://www.wanandroid.com/

3.2定義接口
public interface RetrofitHttpService {

    @GET()
    Call<ResponseBody> executGet(@Url String url);

    @GET()
    Call<ResponseBody> executGet(@Url String url, @QueryMap Map<String, String> maps);



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


    @POST()
    Call<ResponseBody> executeJsonPost(@Url String url, @Body RequestBody body);


    @GET
    Call<ResponseBody>  loadBitmap(@Url String url);


    @Streaming
    @GET
    Call<ResponseBody>  downloadFile(@Url String url);
    }
}

還有一種寫法

public interface WeatherService {
@GET()
Call<ResponseBody> getWeatherData(@Url String url);
}

第二種寫法強(qiáng)調(diào)的是獲取天氣數(shù)據(jù)這個接口,如果需要登錄,則又需要新定義一個接口。第一種則是通用寫法,所有的接口都可以用

3.3 接口調(diào)用

get請求

public void requestGetAsyn(String url, Map<String, String> params, final StringCallback callback) {
    RetrofitHttpService service = RetrofitManager.getInstance().create(RetrofitHttpService.class);
    Call<ResponseBody> call = service.executGet(url, params);
    call.enqueue(new Callback<ResponseBody>() {
        @Override
        public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
            if (response.isSuccessful()) {
                try {
                    callback.OnSuccess(response.body().string());
                } catch (IOException e) {
                    e.printStackTrace();
                    callback.OnError("異常信息:" + e.getMessage());
                }
            } else {
                callback.OnError("錯誤碼:" + response.code());
            }

        }

        @Override
        public void onFailure(Call<ResponseBody> call, Throwable t) {
            if (t != null && t.getMessage() != null) {
                callback.OnError(t.getMessage());
            } else {
                callback.OnError(ERROR);
            }

        }
    });
}

post表單提交

public void requestPostAsyn(String url, Map<String, String> params, final StringCallback callback) {
    RetrofitHttpService service = RetrofitManager.getInstance().create(RetrofitHttpService.class);
    Call<ResponseBody> call = service.executePost(url, params);
    call.enqueue(new Callback<ResponseBody>() {
        @Override
        public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {

            if (response.isSuccessful()) {
                try {
                    callback.OnSuccess(response.body().string());
                } catch (IOException e) {
                    e.printStackTrace();
                    callback.OnError("異常信息:" + e.getMessage());
                }
            } else {
                callback.OnError("錯誤碼:" + response.code());
            }

        }

        @Override
        public void onFailure(Call<ResponseBody> call, Throwable t) {
            if (t != null && t.getMessage() != null) {
                callback.OnError(t.getMessage());
            } else {
                callback.OnError(ERROR);
            }

        }
    });  
}

post提交json格式參數(shù)

public void requestPostJsonAsyn(String url, Map<String, String> params, final StringCallback callback) {
    RetrofitHttpService service = RetrofitManager.getInstance().create(RetrofitHttpService.class);
    MediaType JSON = MediaType.parse("application/json");
    JSONObject jsonObject = new JSONObject(params);
    RequestBody requestBody = RequestBody.create(JSON, jsonObject.toString());
    Call<ResponseBody> call = service.executeJsonPost(url, requestBody);
    call.enqueue(new Callback<ResponseBody>() {
        @Override
        public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
            if (response.isSuccessful()) {
                try {
                    callback.OnSuccess(response.body().string());
                } catch (IOException e) {
                    e.printStackTrace();
                    callback.OnError("異常信息:" + e.getMessage());
                }
            } else {
                callback.OnError("錯誤碼:" + response.code());
            }
        }
        @Override
        public void onFailure(Call<ResponseBody> call, Throwable t) {
            if (t != null && t.getMessage() != null) {
                callback.OnError(t.getMessage());
            } else {
                callback.OnError(ERROR);
            }

        }
    });
}

至此,retrofit的基本使用已經(jīng)完事了。

3. 核心類分析

Retrofit
該類包含了下面這些參數(shù)

private final Map<Method, ServiceMethod<?, ?>>     serviceMethodCache = new ConcurrentHashMap<>();
final okhttp3.Call.Factory callFactory;
final HttpUrl baseUrl;
final List<Converter.Factory> converterFactories;
final List<CallAdapter.Factory> callAdapterFactories;
final @Nullable Executor callbackExecutor;
final boolean validateEagerly;

我們先來看看Retrofit的Builder這個內(nèi)部類,這里面提供了許多設(shè)置上述參數(shù)的方法,就不說了,主要來看看build這個方法。

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

  okhttp3.Call.Factory callFactory = this.callFactory;
  if (callFactory == null) {
    callFactory = new OkHttpClient();
  }

  Executor callbackExecutor = this.callbackExecutor;
  if (callbackExecutor == null) {
    callbackExecutor = platform.defaultCallbackExecutor();
  }

  // Make a defensive copy of the adapters and add the default Call adapter.
  List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(this.callAdapterFactories);
  callAdapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));

  // Make a defensive copy of the converters.
  List<Converter.Factory> converterFactories =
      new ArrayList<>(1 + this.converterFactories.size());

  // Add the built-in converter factory first. This prevents overriding its behavior but also
  // ensures correct behavior when using converters that consume all types.
  converterFactories.add(new BuiltInConverters());
  converterFactories.addAll(this.converterFactories);

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

分析(自上而下看代碼)
當(dāng)baseUrl為null時,會拋異常

callFactory這個其實(shí)指的就是OkHttpClient(繼承自Call.Factory),當(dāng)我們沒有顯示設(shè)置時,則會使用默認(rèn)的client,為了更加方便的控制網(wǎng)絡(luò),建議設(shè)置一個自定義的client,比如設(shè)置超時時間,攔截器,緩存等。

callbackExecutor,我們來看一下默認(rèn)的執(zhí)行器
Platform
該類主要是獲取當(dāng)前程序是java還是android

static class Android extends Platform {
@Override public Executor defaultCallbackExecutor() {
  return new MainThreadExecutor();
}

@Override CallAdapter.Factory defaultCallAdapterFactory(@Nullable Executor callbackExecutor) {
  if (callbackExecutor == null) throw new AssertionError();
  return new ExecutorCallAdapterFactory(callbackExecutor);
}

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

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

明顯看出默認(rèn)的Executor,在主線程中。這就是為什么retrofit不用切換到主線程去返回報文,因為報文的回調(diào)方法已經(jīng)在主線程了。

callAdapterFactories
看代碼,CallAdapter是接口,F(xiàn)actory是該接口的一個內(nèi)部抽象類
不論我們有木有addCallAdapterFactory,都會增加一個默認(rèn)的實(shí)現(xiàn)
ExecutorCallAdapterFactory,該類繼承CallAdapter.Factory,該實(shí)現(xiàn)放在自定義CallAdapter之后
ExecutorCallAdapterFactory
我們只看關(guān)鍵代碼

 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()) {
            // Emulate OkHttp's behavior of throwing/delivering an IOException on 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(new Runnable() {
        @Override public void run() {
          callback.onFailure(ExecutorCallbackCall.this, t);
        }
      });
    }
  });

從這里就看出了報文是從哪個地方返回的

converterFactories
看代碼,Converter是接口,F(xiàn)actory是該接口的一個內(nèi)部抽象類
無論我們有木有addConverterFactory,都會有一個默認(rèn)的實(shí)現(xiàn)
BuiltInConverters,該類繼承Converter. Factory,該實(shí)現(xiàn)添加在自定義的Converter之前。
BuiltInConverters
第一次看這個類的時候不知道它有何用,稍后在來解析。

在來看下mRetrofit.create(service)這個方法

public <T> T create(final Class<T> service) {
Utils.validateServiceInterface(service);
if (validateEagerly) {
  eagerlyValidateMethods(service);
}
return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },
    new InvocationHandler() {
      private final Platform platform = Platform.get();

      @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);
        }
        ServiceMethod<Object, Object> serviceMethod =
            (ServiceMethod<Object, Object>) loadServiceMethod(method);
        OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
        return serviceMethod.adapt(okHttpCall);
      }
    });
}

這里用到了jdk動態(tài)代理方法,根據(jù)傳遞的接口返回一個動態(tài)代理,當(dāng)我們調(diào)用接口的方法時,就會調(diào)用invoke方法

從前面我們知道Retrofit有一個serviceMethodCache,里面保存了一系列的serviceMethod,而serviceMethod包含了http請求相關(guān)的信息

ServiceMethod

static final String PARAM = "[a-zA-Z][a-zA-Z0-9_-]*";
static final Pattern PARAM_URL_REGEX = Pattern.compile("\\{(" + PARAM + ")\\}");
static final Pattern PARAM_NAME_REGEX = Pattern.compile(PARAM);

private final okhttp3.Call.Factory callFactory;
private final CallAdapter<R, T> callAdapter;

private final HttpUrl baseUrl;
private final Converter<ResponseBody, R> responseConverter;
private final String httpMethod;
private final String relativeUrl;
private final Headers headers;
private final MediaType contentType;
private final boolean hasBody;
private final boolean isFormEncoded;
private final boolean isMultipart;
private final ParameterHandler<?>[] parameterHandlers;

再看invoke方法的最后三行代碼
每調(diào)用接口中的一個方法,如果是第一次調(diào)用該方法會根據(jù)當(dāng)前的retrofit和method構(gòu)建出一個serviceMethod對象,并將其保存在緩存中,下次就直接從緩存中區(qū)。
根據(jù)這個serviceMethod構(gòu)建出一個okHttpCall。
最后一句代碼,把一個okHttpCall 類型適配為用戶定義的 service method 的 return type

T adapt(Call<R> call) {
    return callAdapter.adapt(call);
 }

這個callAdapter是一個接口,最終會調(diào)用它的實(shí)現(xiàn)類的adapt方法,如RxJavaCallAdapterFactory,它的adapt方法

 public <R> Observable<Result<R>> adapt(Call<R> call) {
  Observable<Result<R>> observable = Observable.create(new CallOnSubscribe<>(call)) //
      .map(new Func1<Response<R>, Result<R>>() {
        @Override public Result<R> call(Response<R> response) {
          return Result.response(response);
        }
      }).onErrorReturn(new Func1<Throwable, Result<R>>() {
        @Override public Result<R> call(Throwable throwable) {
          return Result.error(throwable);
        }
      });
  if (scheduler != null) {
    return observable.subscribeOn(scheduler);
  }
  return observable;
}

在看ExecutorCallAdapterFactory(默認(rèn)的callAdapter)的adapt方法

public Call<Object> adapt(Call<Object> call) {
    return new ExecutorCallbackCall<>(callbackExecutor, call);
  }

我們這里只探討ExecutorCallAdapterFactory方式的返回類型Call,調(diào)動call.enqueue

@Override public void enqueue(final Callback<T> callback) {
  checkNotNull(callback, "callback == null");

  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()) {
            // Emulate OkHttp's behavior of throwing/delivering an IOException on 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(new Runnable() {
        @Override public void run() {
          callback.onFailure(ExecutorCallbackCall.this, t);
        }
      });
    }
  });
}

這里的delegate.enqueue,其中delegate是Call這個接口,它的實(shí)現(xiàn)類是OkHttpCall,因此最終調(diào)用的就是OkHttpCall的enqueue方法,該方法最終調(diào)用的OkHttpClient的Call.enqueue方法,至此就將交易發(fā)了出去。

4. 總結(jié)

主要關(guān)注2和3
Retrofit的回調(diào)已經(jīng)放在UI線程,無需再轉(zhuǎn)化線程

圖片請求和文件下載
一般我們會選擇一個圖片框架
如果用Retrofit請求圖片和下載文件,只需要將response轉(zhuǎn)化為流即可

response.body().byteStream()   //文件流
responseBody.contentLength()  //總長度

對于圖片,通過Bitmap工具類可以直接將流轉(zhuǎn)化為bitmap
對于文件,將流保存在對應(yīng)的文件目錄即可,同時通過已下載的文件流字節(jié)數(shù)/總長度來計算進(jìn)度

InputStream is =  response.body().byteStream();
byte[] buf = new byte[1024];
long total = responseBody.contentLength();
while ((len = is.read(buf)) != -1) {
     sum += len;
     fos.write(buf, 0, len);
     callback.Progress(sum * 1.0f / total * 100);
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容