Retrofit使用詳解(二)

OKHttp(一)之Calls

OKHttp(二)之Connections

OkHttp(三)之使用方法

OkHttp(四)之?dāng)r截器

OkHttp(五)之HTTPS

Retrofit使用詳解(一)

Retrofit使用詳解(二)

Retrofit使用詳解(三)

Retrofit使用詳解(四)

Retrofit使用詳解(五)

Retrofit使用詳解(六)

同步請(qǐng)求和異步請(qǐng)求

Retrofit支持同步請(qǐng)求和異步請(qǐng)求显歧。

同步請(qǐng)求

使用的同步請(qǐng)求通過定義返回類型來聲明。 下面的示例期望執(zhí)行g(shù)etTasks方法時(shí)返回Task列表。

public interface TaskService {  
    @GET("/tasks")
    Call<List<Task>> getTasks();
}

在Retrofit 2中祷嘶,每個(gè)請(qǐng)求都被包裝到一個(gè)Call對(duì)象中。 實(shí)際的同步或異步請(qǐng)求將在稍后創(chuàng)建的調(diào)用對(duì)象上的所需方法執(zhí)行筹误。 但是思犁,同步和異步請(qǐng)求的接口類在Retrofit 2中是相同的。

同步方法在主線程上執(zhí)行桑嘶。 這意味阻塞UI,并且在此期間不可能進(jìn)行交互躬充。

Note: 警告:同步請(qǐng)求會(huì)觸發(fā)Android 4.0或更高版本上的應(yīng)用崩潰逃顶。 你會(huì)遇到NetworkOnMainThreadException錯(cuò)誤。

同步方法能夠直接返回值充甚,因?yàn)椴僮髟诰W(wǎng)絡(luò)請(qǐng)求期間阻止其他任何操作以政。

對(duì)于非阻塞UI,你必須在一個(gè)單獨(dú)的線程中的請(qǐng)求執(zhí)行伴找。 這意味著盈蛮,你仍然可以在等待響應(yīng)時(shí)與應(yīng)用程序本身進(jìn)行交互。

Get Results from Synchronous Requests

以下代碼片段說明了使用Retrofit執(zhí)行的同步請(qǐng)求:

TaskService taskService = ServiceGenerator.createService(TaskService.class);  
Call<List<Task>> call = taskService.getTasks();  
List<Task>> tasks = call.execute().body();  

在Call對(duì)象上使用.execute()方法,在Retrofit2中執(zhí)行同步請(qǐng)求技矮。反序列化響應(yīng)主體可通過響應(yīng)對(duì)象上的.body()方法獲得抖誉。

Asynchronous Requests

public interface TaskService {  
    @GET("/tasks")
    Call<List<Task>> getTasks();
}

Retrofit在單獨(dú)的線程中執(zhí)行。Callback類是通用的衰倦,并映射您定義的返回類型袒炉。 我們的示例返回一個(gè)任務(wù)列表,Callback在內(nèi)部進(jìn)行映射樊零。

如上所述:Retrofit 2中的接口定義對(duì)于同步和異步請(qǐng)求是相同的我磁。 所需的返回類型被封裝到一個(gè)Call對(duì)象中孽文,實(shí)際的請(qǐng)求執(zhí)行定義它的類型(同步/異步)。

Get Results from Asynchronous Requests

使用異步請(qǐng)求必須實(shí)現(xiàn)兩個(gè)回調(diào)方法:成功和失敗夺艰。 當(dāng)從服務(wù)類調(diào)用異步getTasks()方法時(shí)芋哭,必須實(shí)現(xiàn)回調(diào),并定義一旦請(qǐng)求完成應(yīng)該做什么:

TaskService taskService = ServiceGenerator.createService(TaskService.class);  
Call<List<Task>> call = taskService.getTasks();  
call.enqueue(new Callback<List<Task>>() {  
    @Override
    public void onResponse(Call<List<Task>> call, Response<List<Task>> response) {
        if (response.isSuccessful()) {
            // tasks available
        } else {
            // error response, no access to resource?
        }
    }

    @Override
    public void onFailure(Call<List<Task>> call, Throwable t) {
        // something went completely south (like no internet connection)
        Log.d("Error", t.getMessage());
    }
}

Get Raw HTTP Response

如果你需要原始的HTTP響應(yīng)對(duì)象郁副,只需要定義返回類型為Response.
你可以接收Retrofit 2中原始響應(yīng)主體與定義請(qǐng)求類型(sync / async)的方式相同减牺。 不需要將Response類定義為返回類型,但可以在onResponse()回調(diào)方法中捕獲它存谎。 讓我們看看下面的代碼片段來說明如何獲得原始響應(yīng):

call.enqueue(new Callback<List<Task>>() {  
    @Override
    public void onResponse(Call<List<Task>> call, Response<List<Task>> response) {
        // get raw response
        Response raw = response.raw();
    }

    @Override
    public void onFailure(Call<List<Task>> call, Throwable t) {}
}

在請(qǐng)求體中發(fā)送對(duì)象

Send Objects as Request Body

Retrofit提供了在請(qǐng)求體內(nèi)發(fā)送對(duì)象的能力烹植。 通過使用@Body注釋,可以指定對(duì)象用作HTTP請(qǐng)求主體愕贡。

public interface TaskService {  
    @POST("/tasks")
    Call<Task> createTask(@Body Task task);
}

定義的RestAdapter的轉(zhuǎn)換器(如Gson)會(huì)將對(duì)象映射到JSON草雕,它將最終作為請(qǐng)求的主體發(fā)送到服務(wù)器。

Example

public class Task {  
    private long id;
    private String text;

    public Task(long id, String text) {
        this.id = id;
        this.text = text;
    }
}

創(chuàng)建一個(gè)新的Task對(duì)象固以。

Task task = new Task(1, "my task title");  
Call<Task> call = taskService.createTask(task);  
call.enqueue(new Callback<Task>() {});  

調(diào)用方法createTask會(huì)將Task轉(zhuǎn)換為JSON墩虹。Task的JSON將如下所示:

{
    "id": 1,
    "text": "my task title"
}

添加自定義頭信息

Retrofit提供了兩個(gè)定義HTTP請(qǐng)求標(biāo)頭字段的選項(xiàng):靜態(tài)和動(dòng)態(tài)。 靜態(tài)請(qǐng)求頭不能更改憨琳。請(qǐng)求頭的的鍵和值是固定的诫钓,并與應(yīng)用程序同時(shí)啟動(dòng)。

相反篙螟,動(dòng)態(tài)請(qǐng)求頭必須每次都設(shè)置菌湃。

靜態(tài)請(qǐng)求頭

將API方法的頭和相應(yīng)的值定義為注解。 對(duì)于使用此方法的每個(gè)請(qǐng)求遍略,頭信息會(huì)自動(dòng)通過Retrofit添加惧所。 注解必須是鍵值對(duì),可以有一個(gè)或者多個(gè):

public interface UserService {  
    @Headers("Cache-Control: max-age=640000")
    @GET("/tasks")
    Call<List<Task>> getTasks();
}

上面的示例顯示了靜態(tài)頭的鍵值定義绪杏。 此外下愈,您可以將多個(gè)鍵值字符串作為封裝在大括號(hào){}中的列表傳遞到@Headers注釋。

public interface UserService {  
    @Headers({
        "Accept: application/vnd.yourapi.v1.full+json",
        "User-Agent: Your-App-Name"
    })
    @GET("/tasks/{task_id}")
    Call<Task> getTask(@Path("task_id") long taskId);
}

此外蕾久,您可以通過Retrofit的RequestInterceptor的攔截方法(在Retrofit 2中自定義實(shí)現(xiàn)Interceptor接口)來定義靜態(tài)頭势似。
在Retrofit中必須在OkHttp中添加攔截器。

OkHttpClient.Builder httpClient = new OkHttpClient.Builder();  
httpClient.addInterceptor(new Interceptor() {  
    @Override
    public Response intercept(Interceptor.Chain chain) throws IOException {
        Request original = chain.request();

        Request request = original.newBuilder()
            .header("User-Agent", "Your-App-Name")
            .header("Accept", "application/vnd.yourapi.v1.full+json")
            .method(original.method(), original.body())
            .build();

        return chain.proceed(request);
    }
}

OkHttpClient client = httpClient.build();  
Retrofit retrofit = new Retrofit.Builder()  
    .baseUrl(API_BASE_URL)
    .addConverterFactory(GsonConverterFactory.create())
    .client(client)
    .build();

上面的示例將User-Agent和Accept頭字段設(shè)置為相應(yīng)的值僧著。 這些值與使用RestAdapter(Retrofit 2中的Retrofit)和集成的RequestInterceptor(Retrofit 2中的Interceptor)執(zhí)行的請(qǐng)求一起傳遞履因。

Dynamic Header

動(dòng)態(tài)header是作為參數(shù)傳進(jìn)方法中的。 在執(zhí)行請(qǐng)求之前盹愚,通過Retrofit映射提供的參數(shù)值:

public interface UserService {  
    @GET("/tasks")
    Call<List<Task>> getTasks(@Header("Content-Range") String contentRange);
}

動(dòng)態(tài)請(qǐng)求頭允許你為每個(gè)請(qǐng)求設(shè)置不同的值栅迄。

復(fù)寫Retrofit2中的已經(jīng)存在的請(qǐng)求頭

  • .header(key,value):如果已經(jīng)存在由鍵標(biāo)識(shí)的現(xiàn)有頭杯拐,則用值覆蓋相應(yīng)的值
  • .addHeader(key霞篡,value):添加相應(yīng)的標(biāo)題鍵和值,即使存在具有相同鍵的現(xiàn)有標(biāo)題字段

在攔截器中管理請(qǐng)求頭

添加請(qǐng)求頭

一個(gè)常見的例子是使用授權(quán)頭字段端逼。如果幾乎每個(gè)請(qǐng)求都需要包含授權(quán)的頭字段朗兵,則可以使用攔截器來添加這條信息。 這樣顶滩,就不需要為每個(gè)端點(diǎn)聲明添加@Header注釋余掖。

類似于前邊介紹的,可以直接添加頭信息礁鲁,也可以覆蓋原有的頭信息盐欺。

How to Override Headers

使用OkHttp攔截器允許你修改實(shí)際請(qǐng)求。請(qǐng)求構(gòu)建器具有一個(gè).header(key仅醇,val)方法冗美,它會(huì)將定義的頭添加到請(qǐng)求中。 如果已經(jīng)存在具有相同鍵標(biāo)識(shí)符的現(xiàn)有頭析二,則此方法將覆蓋先前定義的值粉洼。

OkHttpClient.Builder httpClient = new OkHttpClient.Builder();  
httpClient.addInterceptor(new Interceptor() {  
    @Override
    public Response intercept(Interceptor.Chain chain) throws IOException {
        Request original = chain.request();

        // Request customization: add request headers
        Request.Builder requestBuilder = original.newBuilder()
                .header("Authorization", "auth-value"); // <-- this is the important line

        Request request = requestBuilder.build();
        return chain.proceed(request);
    }
});

OkHttpClient client = httpClient.build();  

Retrofit和OkHttp允許你添加多個(gè)具有相同key的頭信息,這將會(huì)覆蓋原有的頭信息叶摄。

How to Not Override Headers

有時(shí)會(huì)使用具有相同名稱的多個(gè)頭属韧。實(shí)際上,我們只知道一個(gè)具體的實(shí)例:Cache-Control頭蛤吓。 HTTP RFC2616指定允許具有相同名稱的多個(gè)標(biāo)頭值宵喂,如果它們可以表示為逗號(hào)分隔列表。

Cache-Control: no-cache  
Cache-Control: no-store  

等同于

Cache-Control: no-cache, no-store  

此時(shí)可以調(diào)用.addHeader()方才來添加頭会傲,而不是覆蓋锅棕。

OkHttpClient.Builder httpClient = new OkHttpClient.Builder();  
httpClient.addInterceptor(new Interceptor() {  
    @Override
    public Response intercept(Interceptor.Chain chain) throws IOException {
        Request original = chain.request();

        // Request customization: add request headers
        Request.Builder requestBuilder = original.newBuilder()
                    .addHeader("Cache-Control", "no-cache")
                    .addHeader("Cache-Control", "no-store");

        Request request = requestBuilder.build();
        return chain.proceed(request);
    }
});

OkHttpClient client = httpClient.build();  
  • .header(key,value):如果已經(jīng)存在由鍵標(biāo)識(shí)的現(xiàn)有頭淌山,則用值覆蓋相應(yīng)的值
  • .addHeader(key哲戚,value):添加相應(yīng)的標(biāo)題鍵和值,即使存在具有相同鍵的現(xiàn)有標(biāo)題字段

使用@HeaderMap添加請(qǐng)求頭

Dynamic Request Headers

前邊文章中顯示的方法都是靜態(tài)的艾岂。 雖然你可以更改請(qǐng)求頭的值顺少,但無(wú)法動(dòng)態(tài)選擇實(shí)際發(fā)送的請(qǐng)求頭。 王浴,@HeaderMap可以讓你在運(yùn)行時(shí)決定哪些頭被添加到你的請(qǐng)求脆炎。

與@Header注釋類似,需要將@HeaderMap聲明為接口參數(shù)之一氓辣。 參數(shù)的類型需要實(shí)現(xiàn)Java Map接口:

public interface TaskService {  
    @GET("/tasks")
    Call<List<Task>> getTasks(
        @HeaderMap Map<String, String> headers
    );
}

使用我們上面聲明的接口非常簡(jiǎn)單秒裕。 您可以創(chuàng)建一個(gè)Map實(shí)例,并根據(jù)您的需要使用值填充它钞啸。 Retrofit將@HeaderMap的每個(gè)非空元素添加為請(qǐng)求標(biāo)頭几蜻。

TaskService taskService = ServiceGenerator.createService(TaskService.class);

Map<String, String> map = new HashMap<>();  
map.put("Page", String.valueOf(page));

if (BuildConfig.DEBUG) {  
    map.put("Accept", "application/vnd.yourapi.v1.full+json");
    map.put("User-Agent", "Future Studio Debug");
}
else {  
    map.put("Accept", "application/json");
    map.put("Accept-Charset", "utf-8");
    map.put("User-Agent", "Future Studio Release");
}

Call<List<Task>> call = taskService.getTasks(map);  
// Use it like any other Retrofit call

多個(gè)具有相同名稱的查詢參數(shù)

Query Parameters

Query parameters 是從客戶端傳遞數(shù)據(jù)到服務(wù)器的最常見的方式喇潘。

https://api.example.com/tasks?id=123  

上面的例子是通過路由"tasks"傳遞數(shù)據(jù)"id=123"到服務(wù)器。

在Retrofit中可以如下寫

public interface TaskService {  
    @GET("/tasks")
    Call<Task> getTask(@Query("id") long taskId);
}

在getTask方法中需要傳入?yún)?shù)"taskId"梭稚,Retrofit會(huì)自動(dòng)轉(zhuǎn)換為"/task?id=<taskid>"形式颖低。

Multiple Query Parameters

一些情況下需要傳遞多個(gè)相同名字的參數(shù)到服務(wù)器,類似于下面的樣子:

https://api.example.com/tasks?id=123&id=124&id=125  

此時(shí)期望服務(wù)器的返回值應(yīng)該是一個(gè)任務(wù)列表對(duì)應(yīng)的id是ids=[123,124,125]弧烤。

在Retrofit中可以很簡(jiǎn)單的做到忱屑,只需要傳遞一個(gè)List即可。

public interface TaskService {  
    @GET("/tasks")
    Call<List<Task>> getTask(@Query("id") List<Long> taskIds);
}

可選查詢參數(shù)

根據(jù)API的設(shè)計(jì)暇昂,有時(shí)候我們需要傳遞可選的參數(shù)到服務(wù)器莺戒。如果你不想傳遞參數(shù),就傳遞null即可急波。
service.getTasks(null);
Retrofit在重新編譯請(qǐng)求時(shí)會(huì)自動(dòng)忽略null的參數(shù)从铲。記住,你不能使用原始數(shù)據(jù)類型來傳遞null澄暮,例如:int,float,long等食店,你必須使用它們的包裝類:Integer,Float,Long等,這樣編譯器不會(huì)報(bào)錯(cuò):

public interface TaskService {  
    @GET("/tasks")
    Call<List<Task>> getTasks(
        @Query("sort") String order,
        @Query("page") Integer page);
}

現(xiàn)在你可以為getTasks方法傳遞null參數(shù)了赏寇。

service.getTasks(null, null);  

傳遞URL表單數(shù)據(jù)

表單請(qǐng)求

在Retrofit添加表單請(qǐng)求只需要添加另外一個(gè)注解將會(huì)直接將你的請(qǐng)求類型轉(zhuǎn)換為"application/x-www-form-urlencoded".如下邊的例子:

public interface TaskService {  
    @FormUrlEncoded
    @POST("tasks")
    Call<Task> createTask(@Field("title") String title);
}

重要的部分是@FormUrlEncoded這個(gè)注解吉嫩。你不能使用get方法時(shí)候添加這個(gè)注解,表單的目的是傳遞數(shù)據(jù)到服務(wù)器嗅定。
此外自娩,必須使用@Field注釋來與您的請(qǐng)求一起發(fā)送的參數(shù)。 將所需的鍵放在@Field(“key”)注釋中以定義參數(shù)名稱渠退。 此外忙迁,將您的值的類型添加為方法參數(shù)。 如果不使用String碎乃,Retrofit將使用Java的String.valueOf(yourObject)方法創(chuàng)建一個(gè)字符串值姊扔。

service.createTask("Research Retrofit form encoded requests");  

生成的結(jié)果是

title=Research+Retrofit+form+encoded+requests  

假如需要傳遞多個(gè)參數(shù),你只需要繼續(xù)添加@Field即可梅誓。

Form Encoded Requests Using an Array of Values

在上邊的例子中使用@Field注解可以添加字符串?dāng)?shù)據(jù)恰梢。但是如果你想要使用對(duì)象而不是字符串類型,Retrofit將會(huì)把你的對(duì)象轉(zhuǎn)換為字符串梗掰。你也可以使用同一個(gè)key傳遞一個(gè)字符串?dāng)?shù)組嵌言。

public interface TaskService {  
    @FormUrlEncoded
    @POST("tasks")
    Call<List<Task>> createTasks(@Field("title") List<String> titles);
}

現(xiàn)在來看一下如何使用

List<String> titles = new ArrayList<>();  
titles.add("Research Retrofit");  
titles.add("Retrofit Form Encoded")

service.createTasks(titles);  

生成的結(jié)果如下:
title=Research+Retrofit&title=Retrofit+Form+Encoded

每個(gè)條目都被轉(zhuǎn)換成了類似于map的鍵值對(duì)形式,鍵值對(duì)與鍵值對(duì)之間用&連接及穗,鍵值對(duì)內(nèi)部用=連接摧茴。

Field Options

@Filed注解有一個(gè)編碼選項(xiàng)encoded,是布爾值埂陆。默認(rèn)是false苛白。

這個(gè)encoded定義的內(nèi)容是你是否已經(jīng)為鍵值對(duì)編碼為url:
@Field(value = "title", encoded = true) String title

Form-Urlencoded vs. Query Parameter

這兩種傳遞數(shù)據(jù)的方式有什么不同:
form-urlencoded: POST
query parameter: GET
使用form-urlencoded方式傳遞數(shù)據(jù)的時(shí)候數(shù)據(jù)存放在請(qǐng)求體內(nèi)娃豹,不會(huì)再url中顯示,使用query parameter方式傳遞參數(shù)時(shí)會(huì)在url中顯示购裙,多用于篩選或指定區(qū)域數(shù)據(jù)查詢懂版。

使用FieldMap發(fā)送表單數(shù)據(jù)

What Is @Fieldmap in Retrofit?

假如有多個(gè)注解,例如添加查詢參數(shù)或者路徑參數(shù)缓窜,使用給定對(duì)象請(qǐng)求數(shù)據(jù),創(chuàng)建已經(jīng)編碼好的請(qǐng)求體谍咆。舉一個(gè)簡(jiǎn)單的例子禾锤,你現(xiàn)在想更新程序中用戶的數(shù)據(jù),你需要請(qǐng)求一個(gè)接口要求是鍵值對(duì)形式上傳的摹察。接口接受一個(gè)JSON字段恩掷,你可以這樣寫:

public interface UserService {  
    @FormUrlEncoded
    @PUT("user")
    Call<User> update(
            @Field("username") String username,
            @Field("name") String name,
            @Field("email") String email,
            @Field("homepage") String homepage,
            @Field("location") String location
    );
}

PUT方法需要多個(gè)參數(shù),例如usernam,email,homepage等供嚎。

缺點(diǎn):每次我們使用新的數(shù)據(jù)發(fā)送更新的時(shí)候黄娘,我們必須要提供每一個(gè)參數(shù)的值,即使他們沒有更改克滴,這樣做很繁瑣逼争。

Retrofit提供了一個(gè)解決上述問題的方案:@FieldMap。

Form Encoded Requests Using FieldMap

有時(shí)候你只需要為某個(gè)用戶更新指定字段劝赔,你可以使用Retrofit的@FieldMao誓焦。你可以使用java標(biāo)準(zhǔn)的Map格式來添加你的鍵值對(duì)。

public interface UserService {  
    @FormUrlEncoded
    @PUT("user")
    Call<User> update(@FieldMap Map<String, String> fields);
}

Note:假如你只需要更新你的username字段着帽,那就沒有必要添加username以外的字段杂伟,你的請(qǐng)求只包含單個(gè)字段。

@FiledMap在應(yīng)用程序中使用的非常廣泛仍翰,但是又一點(diǎn)不好的地方:你不知道哪些字段是允許添加的赫粥,你也不知道字段名稱,這就需要額外的文檔來說明予借。

FieldMap Options

同@Field一樣越平,@FieldMap也包含一個(gè)布爾值encoded,默認(rèn)是false灵迫。

使用方法如下:
@FieldMap(encoded = true) Map<String, String> fields

encode定義了每個(gè)鍵值對(duì)是否已經(jīng)被編碼喧笔。

來看一個(gè)簡(jiǎn)單的例子。要更新username字段的值為marcus-poehls龟再,默認(rèn)情況下會(huì)變成username=marcus-poehls书闸,使用編碼后會(huì)變成username=marcus%2Dpoehls。

為每個(gè)請(qǐng)求添加Query Parameters

你可以通過向OkHttpClient添加一個(gè)新的請(qǐng)求攔截器來實(shí)現(xiàn)利凑。 攔截實(shí)際請(qǐng)求并獲取HttpUrl浆劲。 http url是添加查詢參數(shù)所必需的嫌术,因?yàn)樗鼘⑼ㄟ^附加查詢參數(shù)名稱及其值來更改先前生成的請(qǐng)求網(wǎng)址。

OkHttpClient.Builder httpClient =  
    new OkHttpClient.Builder();
httpClient.addInterceptor(new Interceptor() {  
    @Override
    public Response intercept(Chain chain) throws IOException {
        Request original = chain.request();
        HttpUrl originalHttpUrl = original.url();

        HttpUrl url = originalHttpUrl.newBuilder()
                .addQueryParameter("apikey", "your-actual-api-key")
                .build();

        // Request customization: add request headers
        Request.Builder requestBuilder = original.newBuilder()
                .url(url);

        Request request = requestBuilder.build();
        return chain.proceed(request);
    }
});

一旦您擁有HttpUrl對(duì)象牌借,就可以基于原始的http url對(duì)象創(chuàng)建一個(gè)新的構(gòu)建器度气。 該構(gòu)建器將允許您使用.addQueryParameter(key,val)方法添加其他查詢參數(shù)膨报。 添加查詢參數(shù)后磷籍,使用.build()方法創(chuàng)建新的HttpUrl對(duì)象,該對(duì)象通過使用Request.Builder添加到請(qǐng)求中现柠。 上面的代碼使用基于原始請(qǐng)求的附加參數(shù)構(gòu)建新請(qǐng)求院领,并且只是將網(wǎng)址與新創(chuàng)建的網(wǎng)址進(jìn)行交換。

使用@QueryMap添加多個(gè)查詢參數(shù)

Retrofit允許使用@Query注解來添加查詢參數(shù)够吩。假如有多個(gè)參數(shù)需要傳遞比然,類似于下面:

public interface NewsService() {  
    @GET("/news")
    Call<List<News>> getNews(
            @Query("page") int page,
            @Query("order") String order,
            @Query("author") String author,
            @Query("published_at") Date date,
            …
    );
}

你可以使用null來傳給getNews方法。但是Retrofit提供了一個(gè)更好的方法周循。

How to Use QueryMap

@QueryMap注解使用Map<String,String>來作為參數(shù)强法,每個(gè)非空的key的value都會(huì)被添加進(jìn)去。

public interface NewsService() {  
    @GET("/news")
    Call<List<News>> getNews(
        @QueryMap Map<String, String> options
    );
}

如果你請(qǐng)求作者是Marcus第二頁(yè)的新聞湾笛,你可以只添加page和author字段饮怯,而沒必要再去添加其他字段。

private void fetchNews() {  
    Map<String, String> data = new HashMap<>();
    data.put("author", "Marcus");
    data.put("page", String.valueOf(2));

    // simplified call to request the news with already initialized service
    Call<List<News>> call = newsService.getNews(data);
    call.enqueue(…);
}

最后的結(jié)果是

http://your.api.url/news?page=2&author=Marcus

QueryMap Options

同前面的一樣嚎研,它也擁有布爾值encoded硕淑,默認(rèn)是false。此處不講解詳細(xì)用法了嘉赎。

怎樣在請(qǐng)求中使用動(dòng)態(tài)URL

Use-Case Scenarios

說明一下這個(gè)動(dòng)態(tài)URl是不使用BaseURL的網(wǎng)址置媳。

  1. 上傳文件:假如你的APP允許用戶上傳自己的圖片,你可能回把它們保存到自己的服務(wù)器上公条。
  2. 下載文件:文件能在不同于BaseURL的網(wǎng)址保存

How to Use Dynamic Urls

你可使用@Url注解為請(qǐng)求方法添加動(dòng)態(tài)網(wǎng)址:

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

上邊的@GET注解后邊并沒有添加路由參數(shù)拇囊,它會(huì)自己添加@Url注解的參數(shù)作為請(qǐng)求地址。

How Urls Resolve Against Your Base Url

Retrofit2使用OkHttp的httpurl解析站點(diǎn)靶橱。
來看第一個(gè)例子:

Retrofit retrofit = Retrofit.Builder()  
    .baseUrl("https://your.api.url/");
    .build();

UserService service = retrofit.create(UserService.class);  
service.profilePicture("https://s3.amazon.com/profile-picture/path");

// request url results in:
// https://s3.amazon.com/profile-picture/path

因?yàn)槟闶褂昧艘粋€(gè)完全的地址(https://s3.amazon.com/profile-picture/path),Retrofit會(huì)替換掉BaseUrl然后使用你輸入的地址寥袭。

來看第二個(gè)例子

Retrofit retrofit = Retrofit.Builder()  
    .baseUrl("https://your.api.url/");
    .build();

UserService service = retrofit.create(UserService.class);  
service.profilePicture("profile-picture/path");

// request url results in:
// https://your.api.url/profile-picture/path

這個(gè)例子中你添加的參數(shù)被拼接到BaseURL后邊。

來看第三個(gè)例子

Retrofit retrofit = Retrofit.Builder()  
    .baseUrl("https://your.api.url/v2/");
    .build();

UserService service = retrofit.create(UserService.class);  
service.profilePicture("/profile-picture/path");

// request url results in:
// https://your.api.url/profile-picture/path

第二個(gè)和第三個(gè)例子之間的區(qū)別是:我們添加了v2 /到BaseURl关霸,并使用/在路徑前面传黄。 實(shí)際上,這將導(dǎo)致相同的最終請(qǐng)求url队寇,因?yàn)橐蚤_頭的斜杠開頭的端點(diǎn)url將僅附加到基本url的主機(jī)url膘掰。 當(dāng)對(duì)端點(diǎn)網(wǎng)址使用前導(dǎo)斜杠時(shí),將忽略主機(jī)網(wǎng)址后面的所有內(nèi)容。 您可以通過從您的端點(diǎn)刪除前導(dǎo)/來解決您的問題识埋。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末凡伊,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子窒舟,更是在濱河造成了極大的恐慌系忙,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,252評(píng)論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件惠豺,死亡現(xiàn)場(chǎng)離奇詭異银还,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)洁墙,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,886評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門蛹疯,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人扫俺,你說我怎么就攤上這事苍苞」毯玻” “怎么了狼纬?”我有些...
    開封第一講書人閱讀 168,814評(píng)論 0 361
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)骂际。 經(jīng)常有香客問我疗琉,道長(zhǎng),這世上最難降的妖魔是什么歉铝? 我笑而不...
    開封第一講書人閱讀 59,869評(píng)論 1 299
  • 正文 為了忘掉前任盈简,我火速辦了婚禮,結(jié)果婚禮上太示,老公的妹妹穿的比我還像新娘柠贤。我一直安慰自己,他們只是感情好类缤,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,888評(píng)論 6 398
  • 文/花漫 我一把揭開白布臼勉。 她就那樣靜靜地躺著,像睡著了一般餐弱。 火紅的嫁衣襯著肌膚如雪宴霸。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,475評(píng)論 1 312
  • 那天膏蚓,我揣著相機(jī)與錄音瓢谢,去河邊找鬼。 笑死驮瞧,一個(gè)胖子當(dāng)著我的面吹牛氓扛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播论笔,決...
    沈念sama閱讀 41,010評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼幢尚,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼破停!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起尉剩,我...
    開封第一講書人閱讀 39,924評(píng)論 0 277
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤真慢,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后理茎,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體黑界,經(jīng)...
    沈念sama閱讀 46,469評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,552評(píng)論 3 342
  • 正文 我和宋清朗相戀三年皂林,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了朗鸠。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,680評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡础倍,死狀恐怖烛占,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情沟启,我是刑警寧澤忆家,帶...
    沈念sama閱讀 36,362評(píng)論 5 351
  • 正文 年R本政府宣布,位于F島的核電站德迹,受9級(jí)特大地震影響芽卿,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜胳搞,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,037評(píng)論 3 335
  • 文/蒙蒙 一卸例、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧肌毅,春花似錦筷转、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,519評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至摊滔,卻和暖如春阴绢,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背艰躺。 一陣腳步聲響...
    開封第一講書人閱讀 33,621評(píng)論 1 274
  • 我被黑心中介騙來泰國(guó)打工呻袭, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人腺兴。 一個(gè)月前我還...
    沈念sama閱讀 49,099評(píng)論 3 378
  • 正文 我出身青樓左电,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子篓足,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,691評(píng)論 2 361

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

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理段誊,服務(wù)發(fā)現(xiàn),斷路器栈拖,智...
    卡卡羅2017閱讀 134,713評(píng)論 18 139
  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,312評(píng)論 25 707
  • 整體Retrofit內(nèi)容如下: 1连舍、Retrofit解析1之前哨站——理解RESTful2、Retrofit解析2...
    隔壁老李頭閱讀 15,091評(píng)論 4 39
  • 〖各種繞〗?「簡(jiǎn)化」 一些看起來復(fù)雜的圖樣 只要按解構(gòu)步驟 一筆一劃畫出來 過程其實(shí)幾簡(jiǎn)單
    肥鴿子麻麻閱讀 308評(píng)論 4 2
  • 《今天的花店沒有丁香》 金色的陽(yáng)光穿過頭頂灰色的天空涩哟,落在這一座鋼筋水泥的森林索赏,鏤空他的掌心,鋪在他的眼睛上贴彼,熠熠...
    臨江渚雨閱讀 228評(píng)論 0 0