同步請(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)址置媳。
- 上傳文件:假如你的APP允許用戶上傳自己的圖片,你可能回把它們保存到自己的服務(wù)器上公条。
- 下載文件:文件能在不同于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)/來解決您的問題识埋。