Retrofit 簡介 wiki 文檔 源碼解析 MD

Markdown版本筆記 個人GitHub首頁 個人博客 個人微信 個人郵箱
MyAndroidBlogs baiqiantao baiqiantao bqt20094 baiqiantao@sina.com

目錄

Retrofit

Type-safe HTTP client for Android and Java by Square, Inc.java

GitHub主頁
WIKI
官網&簡易教程
系列教程
JAR包 android

Retrofit requires at minimum Java 7 or Android 2.3.
Snapshots of the development version are available in Sonatype's snapshots repository.git

compile 'com.squareup.retrofit2:retrofit:2.3.0'
compile 'com.squareup.retrofit2:converter-gson:2.3.0' //Converters 轉換器

ProGuard 混淆github

-dontwarn okio.**
-dontwarn javax.annotation.**

Retrofit uses Okio under the hood(在後臺,在底層), so you may want to look at its ProGuard rules as well.web

Retrofit 是一個 RESTful(一種架構風格)的 HTTP 網絡請求框架的封裝。注意這裏並無說它是網絡請求框架,主要緣由在於網絡請求的工做並非Retrofit 來完成的。Retrofit2.0 內置 OkHttp,Retrofit 得益於 OkHttp 的優點,較之於 Volley 是一種更加先進的網絡框架。json

Retrofit 專一於接口的封裝,OkHttp 專一於網絡請求的高效,兩者分工協做api

咱們的應用程序經過 Retrofit 請求網絡,其實是使用 Retrofit 接口層封裝請求參數、Header、Url 等信息,以後由 OkHttp 完成後續的請求操做,在服務端返回數據以後,OkHttp 將原始的結果交給 Retrofit,Retrofit 根據用戶的需求對結果進行解析的過程。服務器

【Retrofit 2.0的變化】
在Retrofit 2.0中,最大的改動莫過於減少庫的體積。微信

  • 首先,Retrofit 2.0去掉了對全部的HTTP客戶端的兼容,而鍾情於OkHttpClient一個,極大地減小了各類適配代碼
  • 其次,拆庫,好比將對RxJava的支持設置爲可選(須要額外引入庫)
  • 再者,將各個序列化、反序列化轉換器支持設置爲可選(須要額外引入庫)

WiKi 使用指導

Call Adapters

Retrofit is pluggable allowing different execution mechanisms and their libraries to be used for performing the HTTP call. This allows API requests to seamlessly compose with any existing threading model and/or task framework in the rest of your app.網絡

Retrofit是可插拔的,容許不一樣的執行機制及其庫用於執行HTTP調用。這容許API請求與您應用程序其他部分中的,任何現有線程模型,和/或任務框架無縫組合。

These are called call adapters, and Retrofit includes a few first-party modules for popular frameworks:

這些被稱爲call適配器,而Retrofit爲當前很是流行的框架提供了一些第一方模塊(官方構件):

  • RxJava Observable & Single - com.squareup.retrofit2:adapter-rxjava
  • RxJava2 Observable, Flowable, Single, Completable & Maybe -com.squareup.retrofit2:adapter-rxjava2
  • Guava ListenableFuture - com.squareup.retrofit2:adapter-guava
  • Java 8 CompletableFuture - com.squareup.retrofit2:adapter-java8

Various third-party adapters have been created by the community for other libraries:
社區也已經爲其餘庫建立了各類的第三方適配器

Converters 轉換器

Retrofit is pluggable allowing different serialization formats and their libraries to be used for converting Java types to their HTTP representation and parsing HTTP entities back into Java types.

Retrofit 是可插拔的,容許不一樣的序列化格式及其庫,用於將Java類型轉換爲其HTTP表示形式,並將HTTP實體解析爲Java類型。

These are called converters, and Retrofit includes a few first-party modules for popular frameworks:

這些被稱爲轉換器,而Retrofit爲當前很是流行的框架提供了一些第一方模塊(官方構件),:

  • Gson - com.squareup.retrofit2:converter-gson
  • Jackson - com.squareup.retrofit2:converter-jackson
  • Moshi - com.squareup.retrofit2:converter-moshi
  • Protobuf - com.squareup.retrofit2:converter-protobuf
  • Wire - com.squareup.retrofit2:converter-wire
  • Simple Framework - com.squareup.retrofit2:converter-simplexml
  • Scalars - com.squareup.retrofit2:converter-scalars

Two delegating converters are also provided:

另外,還提供了兩個委託轉換器:

  • Guava's Optional<T> - com.squareup.retrofit2:converter-guava
  • Java 8's Optional<T> - com.squareup.retrofit2:converter-java8

These differ from the normal converters in that they don't actually convert bytes to object. Instead, they delegate to a normal converter for that and then wrap the optionally-nullable resulting value into an Optional.

這些與正常轉換器不一樣之處在於,它們實際上並不將字節轉換爲對象。 相反,它們委託給一個正常的轉換器,而後將可選的可空值結果值包裝爲可選。

Various third-party converters have been created by the community for other libraries and serialization formats:

社區也已經爲其餘庫和序列化格式建立了各類的第三方轉換器:

  • LoganSquare - com.github.aurae.retrofit2:converter-logansquare
  • FastJson - org.ligboy.retrofit2:converter-fastjson or org.ligboy.retrofit2:converter-fastjson-android

Retrofit Tutorials 教程資源

There are various Retrofit tutorials spread around the web and everyone is looking for help on different sites like Retrofit’s GitHub issues or Stackoverflow. Actually, there’s a tutorial series with more than 47 Retrofit guides available at Future Studio. Those guys are totally into Retrofit and help the community grow, make progress on problems and be awesome!

有各類各樣的Retrofit教程遍及網絡,每一個人都在不一樣的網站尋找幫助,如Retrofit的GitHub issues或Stackoverflow。 實際上,在Future Studio上有一個具備超過47個可用的Retrofit指南的系列教程。 這些傢伙徹底進入了Retrofit,而且幫助社區發展,在解決問題上取得進展(大有裨益),而且很棒!

查找有關如下主題的指南:

  • Getting Started with Retrofit 入門
  • Retrofit 2 Upgrade Guide from 1.x 升級指南
  • Handle authentication(處理認證) with Retrofit (Basic, custom OAuth 2, Token based, Hawk)
  • Upload & download files
  • Improve your development and debugging flow to test your app against multiple environments- and many more! 改進您的開發和調試流程,以測試您的應用程序對多個環境的適應 - 以及更多!
  • Error Handling

You’ll find a lot more guides on various topics, have a look and benefit from all the solutions.

您能夠在各類主題中找到更多指南,看一看並從全部這些解決方案中獲益。

Enjoy coding and make your app rock!

享受編碼,並讓你的應用程序開始搖滾吧!

官網使用教程

官網文檔原文

Introduction 基本使用介紹

Retrofit turns your HTTP API into a Java interface.

Retrofit能夠將你的HTTP API轉化爲JAVA的接口

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的create方法,就能生成一個GitHubService接口的實現

Retrofit retrofit = new Retrofit.Builder()
    .baseUrl("***")
    .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.

每個"來自建立的GitHubService接口的"Call對象,均可以向遠程Web服務器發出同步或異步的HTTP請求。

Call<List<Repo>> repos = service.listRepos("octocat");

Use annotations to describe the HTTP request:

  • URL parameter replacement and query parameter support。
  • Object conversion to request body (e.g., JSON, protocol buffers)。
  • Multipart request body and file upload。

Retrofit使用註解來描述HTTP請求:

  • URL參數的替換和query參數的支持
  • 對象轉化爲請求體(如:JSON,protocol buffers等)
  • 多重請求體和文件上傳

API Declaration 方法聲明

Annotations on the interface methods and its parameters indicate how a request will be handled.

接口方法上的註解及其參數,代表一個請求須要怎麼樣被處理。

REQUEST METHOD 請求方法
Every method must have an HTTP annotation that provides the request method and relative URL. There are five built-in annotations: GET, POST, PUT, DELETE, and HEAD. The relative URL of the resource is specified in the annotation.

每個方法必需要有一個HTTP註解,來標明請求的方式和相對URL。有五種內置的註解:GET、POST、PUT、DELETE以及HEAD。資源的相對URL須要在註解裏面指定:

@GET("users/list")

You can also specify query parameters in the URL.

你也能夠將query參數直接寫在URL裏:

@GET("users/list?sort=desc")

URL MANIPULATION 操做
A request URL can be updated dynamically using replacement blocks and parameters on the method. A replacement block is an alphanumeric string surrounded by { and }. A corresponding parameter must be annotated with @Path using the same string.

一個請求的URL能夠經過"替換塊和方法的參數"來進行動態的更新。替換塊是由被{}包裹起來的"字母數字字符串"。相應的參數必須使用@Path來註解一樣的字符串。

@GET("group/{id}/users")
Call<List<User>> groupList(@Path("id") int groupId);

Query parameters can also be added.

Query參數也能同時被添加。

@GET("group/{id}/users")
Call<List<User>> groupList(@Path("id") int groupId, @Query("sort") String sort);

For complex query parameter combinations a Map can be used.

對於複雜的query參數,能夠用Map來構建

@GET("group/{id}/users")
Call<List<User>> groupList(@Path("id") int groupId, @QueryMap Map<String, String> options);

REQUEST BODY 請求體
An object can be specified for use as an HTTP request body with the @Body annotation.

能夠經過@Body註解來指定一個對象做爲HTTP請求主體

@POST("users/new")
Call<User> createUser(@Body User user);

The object will also be converted using a converter specified on the Retrofit instance. If no converter is added, only RequestBody can be used.

這個對象會被Retrofit實例中指定的converter進行轉化。若是沒有給Retrofit實例添加任何converter,則只能使用RequestBody。

FORM ENCODED AND MULTIPART 表單編碼和MULTIPART
Methods can also be declared to send form-encoded and multipart data.

方法也能夠經過聲明來發送form-encoded和multipart類型的數據。

Form-encoded data is sent when @FormUrlEncoded is present on the method. Each key-value pair is annotated with @Field containing the name and the object providing the value.

當方法中存在@FormUrlEncoded註解時,會發送表單編碼數據。每一個鍵值對都(須要)用@Filed來註解,其中包含名稱和提供該值對象。

@FormUrlEncoded
@POST("user/edit")
Call<User> updateUser(@Field("first_name") String first, @Field("last_name") String last);

Multipart requests are used when @Multipart is present on the method. Parts are declared using the @Part annotation.

當方法中存在@Multipart註解時,將使用Mutipart請求。Parts須要使用@Part註解來聲明。

@Multipart
@PUT("user/photo")
Call<User> updateUser(@Part("photo") RequestBody photo, @Part("description") RequestBody description);

Multipart parts use one of Retrofit's converters or they can implement RequestBody to handle their own serialization.

多個部件使用Retrofit其中的一個轉換器,或者他們能夠實現RequestBody來處理本身的序列化。

HEADER MANIPULATION 頭部操做
You can set static headers for a method using the @Headers annotation.

你能夠經過使用@Headers註解來爲一個方法設置靜態頭。

@Headers("Cache-Control: max-age=640000")
@GET("widget/list")
Call<List<Widget>> widgetList();

多個靜態頭

@Headers({ "Accept: application/vnd.github.v3.full+json", "User-Agent: Retrofit-Sample-App" })
@GET("users/{username}")
Call<User> getUser(@Path("username") String username);

Note that headers do not overwrite each other. All headers with the same name will be included in the request.

請注意,頭部參數並不會相互覆蓋。具備同一個名稱的全部頭參數都會被包含進請求裏面(即:容許key重複)。

A request Header can be updated dynamically using the @Header annotation. A corresponding parameter must be provided to the @Header. If the value is null, the header will be omitted. Otherwise, toString will be called on the value, and the result used.

可使用@Header註解動態更新請求頭。 相應的參數必須提供給 @Header 註解。 若是這個值爲null,那麼這個頭部參數就會被忽略。 不然,值的 toString 方法將會被調用,而且使用此結果。

@GET("user")
Call<User> getUser(@Header("Authorization") String authorization)

Headers that need to be added to every request can be specified using an OkHttp interceptor.

可使用OkHttp攔截器來指定須要添加到每一個請求中的頭部參數。

SYNCHRONOUS VS. ASYNCHRONOUS 同步 VS 異步
Call instances can be executed either synchronously or asynchronously. Each instance can only be used once, but calling clone() will create a new instance that can be used.

你能夠同步或者異步地執行Call實例。每一個實例只能被使用一次,可是調用 clone() 後將會建立一個可使用的新的實例。

On Android, callbacks will be executed on the main thread. On the JVM, callbacks will happen on the same thread that executed the HTTP request.

在Android中,callback將會在主線程中執行;而在JVM環境中,callback將發生在和執行Http請求相同的那個線程中。

Retrofit Configuration 配置

Retrofit is the class through which your API interfaces are turned into callable objects. By default, Retrofit will give you sane defaults for your platform but it allows for customization.

Retrofit是將你定義的API接口轉換爲可調用對象的類。 默認狀況下,Retrofit會提供給你"對您的平臺來講"比較理智的默認值,但它容許自定義。

CONVERTERS 轉換器
By default, Retrofit can only deserialize HTTP bodies into OkHttp's ResponseBody type and it can only accept its RequestBody type for @Body.

默認狀況下,Retrofit只能將HTTP消息體反序列化爲OKHttp的 ResonseBody 類型,並且只能接收 RequestBody 類型做爲 @Body

Converters can be added to support other types. Six sibling modules adapt popular serialization libraries for your convenience.

能夠添加轉換器來支持其餘類型。 如下六個同級模塊,採用了經常使用的序列化庫,來爲你提供方便。

  1. Gson: com.squareup.retrofit2:converter-gson
  2. Jackson: com.squareup.retrofit2:converter-jackson
  3. Moshi: com.squareup.retrofit2:converter-moshi
  4. Protobuf: com.squareup.retrofit2:converter-protobuf
  5. Wire: com.squareup.retrofit2:converter-wire
  6. Simple XML: com.squareup.retrofit2:converter-simplexml

Here's an example of using the GsonConverterFactory class to generate an implementation of the GitHubService interface which uses Gson for its deserialization.

下面提供一個使用GsonConverterFactory類生成 GitHubService 的接口實現(經過使用Gson反序列化)的例子。
如下是使用GsonConverterFactory類生成使用Gson進行反序列化的GitHubService接口的實現的示例。

Retrofit retrofit = new Retrofit.Builder()
    .baseUrl("https://api.github.com")
    .addConverterFactory(GsonConverterFactory.create())//GsonConverterFactory
    .build();
GitHubService service = retrofit.create(GitHubService.class);

CUSTOM CONVERTERS 自定義轉化器
If you need to communicate with an API that uses a content-format that Retrofit does not support out of the box (e.g. YAML, txt, custom format) or you wish to use a different library to implement an existing format, you can easily create your own converter. Create a class that extends the Converter.Factory class and pass in an instance when building your adapter.

若是你須要與 沒有使用Retrofit提供的內容格式的API 進行交互(例如YAML、txt、或自定義格式),或者是你但願使用一個不一樣的庫 來實現現有的格式,你能夠輕鬆建立你本身的轉化器。你須要建立一個繼承自Converter.Factory的類,而且在構建適配器的時候傳遞一個實例。

Retrofit 源碼解析

Retrofit是如何建立接口實例的

使用Retrofit時,咱們須要先去定義一個接口,而後能夠經過調用retrofit.create(IUserBiz.class)方法,獲得一個接口的實例,最後經過該實例執行咱們的操做,那麼Retrofit如何實現咱們指定接口的實例呢?

其實原理是:動態代理

先看一個例子:

public class Test {
    public static void main(String[] args) {
        MInterface mInterface = (MInterface) Proxy.newProxyInstance(MInterface.class.getClassLoader(),//
                new Class<?>[] { MInterface.class }, new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        System.out.println("方法名:" + method.getName());//mMethod
                        System.out.println("參數列表:" + Arrays.toString(method.getParameters()));//[int arg0, java.lang.String arg1]
                        System.out.println("參數值:" + (Integer) args[0] + " , " + (String) args[1]);//28 , 包青天
                        GET get = method.getAnnotation(GET.class);
                        System.out.println("註解內容:" + get.value());//我是註解內容
                        return null;
                    }
                });
        mInterface.mMethod(28, "包青天");
    }
}
interface MInterface {
    @GET("我是註解內容")
    void mMethod(int i, String s);
}
@Retention(RetentionPolicy.RUNTIME)
@interface GET {
    String value();
}

能夠看到咱們經過Proxy.newProxyInstance產生的代理類,當調用接口的任何方法時,都會調用InvocationHandler#invoke方法,在這個方法中能夠拿到傳入的參數,註解等。因此Retrofit也能夠經過一樣的方式,在invoke方法裏面,拿到全部的參數、註解信息,而後就能夠去構造RequestBody,再去構建Request,獲得Call對象封裝後返回。

下面看retrofit#create的源碼結構:

public <T> T create(final Class<T> service) {
    //***
    return Proxy.newProxyInstance(service.getClassLoader(), new Class[]{service}, new InvocationHandler() {
        public Object invoke(Object proxy, Method method, Object... args) throws Throwable {
             //***
        }
    });
}

到這裏,你應該明白Retrofit爲咱們接口生成實例對象並不神奇,僅僅是使用了Proxy這個類的API而已,而後在invoke方法裏面拿到足夠的信息去構建最終返回的Call而已。

Retrofit對象是如何構建的

這裏依然是經過構造者模式進行構建Retrofit對象,其內部的成員變量是比較少的,咱們直接看build()方法:

public Retrofit build() {
    if(this.baseUrl == null) throw new IllegalStateException("Base URL required.");//baseUrl必須指定
    else {
        //若是你須要對okhttpclient進行詳細的設置,須要構建OkHttpClient對象,而後經過callFactory方法傳入,不然new一個默認的OkHttpClient
        okhttp3.Call.Factory callFactory = this.callFactory;
        if(callFactory == null) callFactory = new OkHttpClient();//OkHttpClient即爲Factory的一個實現類

        //Executor用來將回調傳遞到UI線程,這裏可能會利用platform對象對平臺進行判斷,而後根據不一樣的平臺將回調傳遞到不一樣的線程
        Executor callbackExecutor = this.callbackExecutor;
        if(callbackExecutor == null) callbackExecutor = this.platform.defaultCallbackExecutor();

        //對Call進行轉化,如轉換爲Observable後可以使用RxJava
        ArrayList adapterFactories = new ArrayList(this.adapterFactories);
        adapterFactories.add(this.platform.defaultCallAdapterFactory(callbackExecutor));

        //用於將 請求體/響應體 轉換爲咱們想要的類型,好比轉換後可經過Gson序列號/反序列化
        ArrayList converterFactories = new ArrayList(this.converterFactories);
        return new Retrofit((Factory)callFactory, this.baseUrl, converterFactories, adapterFactories, callbackExecutor, this.validateEagerly);
    }
}

Call對象是如何構建的

咱們構造完成retrofit,就能夠利用retrofit.create方法去構建接口的實例了,上面咱們已經分析了這個環節利用了動態代理,並且咱們也分析了具體的Call的構建流程在invoke方法中,下面看一下retrofit.create方法的完整代碼:

public <T> T create(final Class<T> service) {
    Utils.validateServiceInterface(service);
    if(this.validateEagerly) this.eagerlyValidateMethods(service);

    return Proxy.newProxyInstance(service.getClassLoader(), new Class[]{service}, new InvocationHandler() {
        private final Platform platform = Platform.get();

        public Object invoke(Object proxy, Method method, Object... args) throws Throwable {
            if(method.getDeclaringClass() == Object.class) {
                return method.invoke(this, args);
            } else if(this.platform.isDefaultMethod(method)) {
                return this.platform.invokeDefaultMethod(method, service, proxy, args);
            } else {
                //根據咱們的method將其包裝成ServiceMethod,ServiceMethod主要是經過解析咱們方法上的註解最終構建一個Request對象
                ServiceMethod serviceMethod = Retrofit.this.loadServiceMethod(method);
                //經過ServiceMethod和方法的參數構造OkHttpCall對象,構造函數僅僅是簡單的賦值
                OkHttpCall okHttpCall = new OkHttpCall(serviceMethod, args);
                //將OkHttpCall進行代理包裝,相似裝飾者模式,只不過將其執行時的回調經過callbackExecutor進行回調到UI線程中去了
                return serviceMethod.callAdapter.adapt(okHttpCall);//ExecutorCallbackCall類型的Call對象
            }
        }
    });
}

2017-9-13

相關文章
相關標籤/搜索