okhttp文件上傳進度
① okhttp請求網路怎麼設置請求超時
OkHttp 處理了很多網路疑難雜症:會從很多常用的連接問題中自動恢復。如果您的伺服器配置了多個IP地址,當第一個IP連接失敗的時候,OkHttp會自動嘗試下一個IP。OkHttp還處理了代理伺服器問題和SSL握手失敗問題。
OkHttp是一個相對成熟的解決方案,據說Android4.4的源碼中可以看到HttpURLConnection已經替換成OkHttp實現了。所以我們更有理由相信OkHttp的強大。
1、HTTP請求方法
同步GET請求
private final OkHttpClient client = new OkHttpClient();
public void run() throws Exception {
Request request = new Request.Builder()
.url("http://publicobject.com/helloworld.txt")
.build();
Response response = client.newCall(request).execute();
if (!response.isSuccessful())
throw new IOException("Unexpected code " + response);
Headers responseHeaders = response.headers();
for (int i = 0; i < responseHeaders.size(); i++) {
System.out.println(responseHeaders.name(i) + ": " + responseHeaders.value(i));
}
System.out.println(response.body().string());
}
Response類的string()方法會把文檔的所有內容載入到內存,適用於小文檔,對應大於1M的文檔,應 使用流()的方式獲取。
response.body().byteStream()
非同步GET請求
private final OkHttpClient client = new OkHttpClient();
public void run() throws Exception {
Request request = new Request.Builder()
.url("http://publicobject.com/helloworld.txt")
.build();
client.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Request request, IOException e) {
e.printStackTrace();
}
@Override
public void onResponse(Response response) throws IOException {
if (!response.isSuccessful()) {
throw new IOException("Unexpected code " + response);
}
Headers responseHeaders = response.headers();
for (int i = 0; i < responseHeaders.size(); i++) {
System.out.println(responseHeaders.name(i) + ": " + responseHeaders.value(i));
}
System.out.println(response.body().string());
}
});
}
讀取響應會阻塞當前線程,所以發起請求是在主線程,回調的內容在非主線程中。
POST方式提交字元串
private static final MediaType MEDIA_TYPE_MARKDOWN
= MediaType.parse("text/x-markdown; charset=utf-8");
private final OkHttpClient client = new OkHttpClient();
public void run() throws Exception {
String postBody = ""
+ "Releases\n"
+ "--------\n"
+ "\n"
+ " * _1.0_ May 6, 2013\n"
+ " * _1.1_ June 15, 2013\n"
+ " * _1.2_ August 11, 2013\n";
Request request = new Request.Builder()
.url("https://api.github.com/markdown/raw")
.post(RequestBody.create(MEDIA_TYPE_MARKDOWN, postBody))
.build();
Response response = client.newCall(request).execute();
if (!response.isSuccessful())
throw new IOException("Unexpected code " + response);
System.out.println(response.body().string());
}
因為整個請求體都在內存中,應避免提交1M以上的文件。
POST方式提交流
private final OkHttpClient client = new OkHttpClient();
public void run() throws Exception {
RequestBody requestBody = new RequestBody() {
@Override
public MediaType contentType() {
return MEDIA_TYPE_MARKDOWN;
}
@Override
public void writeTo(BufferedSink sink) throws IOException {
sink.writeUtf8("Numbers\n");
sink.writeUtf8("-------\n");
for (int i = 2; i <= 997; i++) {
sink.writeUtf8(String.format(" * %s = %s\n", i, factor(i)));
}
}
private String factor(int n) {
for (int i = 2; i < n; i++) {
int x = n / i;
if (x * i == n) return factor(x) + " × " + i;
}
return Integer.toString(n);
}
};
Request request = new Request.Builder()
.url("https://api.github.com/markdown/raw")
.post(requestBody)
.build();
Response response = client.newCall(request).execute();
if (!response.isSuccessful())
throw new IOException("Unexpected code " + response);
System.out.println(response.body().string());
}
使用Okio框架以流的形式將內容寫入,這種方式不會出現內存溢出問題。
POST方式提交文件
public static final MediaType MEDIA_TYPE_MARKDOWN
= MediaType.parse("text/x-markdown; charset=utf-8");
private final OkHttpClient client = new OkHttpClient();
public void run() throws Exception {
File file = new File("README.md");
Request request = new Request.Builder()
.url("https://api.github.com/markdown/raw")
.post(RequestBody.create(MEDIA_TYPE_MARKDOWN, file))
.build();
Response response = client.newCall(request).execute();
if (!response.isSuccessful())
throw new IOException("Unexpected code " + response);
System.out.println(response.body().string());
}
POST方式提交表單
private final OkHttpClient client = new OkHttpClient();
public void run() throws Exception {
RequestBody formBody = new FormEncodingBuilder()
.add("search", "Jurassic Park")
.build();
Request request = new Request.Builder()
.url("https://en.wikipedia.org/w/index.php")
.post(formBody)
.build();
Response response = client.newCall(request).execute();
if (!response.isSuccessful())
throw new IOException("Unexpected code " + response);
System.out.println(response.body().string());
}
表單的每個Names-Values都進行了URL編碼。如果伺服器端介面未進行URL編碼,可定製個 FormBuilder。
文件上傳(兼容html文件上傳)
private static final String IMGUR_CLIENT_ID = "...";
private static final MediaType MEDIA_TYPE_PNG = MediaType.parse("image/png");
private final OkHttpClient client = new OkHttpClient();
public void run() throws Exception {
// Use the imgur image upload API as documented at https://api.imgur.com/endpoints/image
RequestBody requestBody = new MultipartBuilder()
.type(MultipartBuilder.FORM)
.addPart(
Headers.of("Content-Disposition", "form-data; name=\"title\""),
RequestBody.create(null, "Square Logo"))
.addPart(
Headers.of("Content-Disposition", "form-data; name=\"image\""),
RequestBody.create(MEDIA_TYPE_PNG, new File("website/static/logo-square.png")))
.build();
Request request = new Request.Builder()
.header("Authorization", "Client-ID " + IMGUR_CLIENT_ID)
.url("https://api.imgur.com/3/image")
.post(requestBody)
.build();
Response response = client.newCall(request).execute();
if (!response.isSuccessful())
throw new IOException("Unexpected code " + response);
System.out.println(response.body().string());
}
② okhttp最大支持上傳多大的文件
/**
* 上傳文件
* @param actionUrl 連接地址
* @param paramsMap 參數
* @param callback 回調
* @param <T>
*/
public static <T>void upLoadFile(String actionUrl, HashMap<String, Object> paramsMap, Callback callback) {
// RequestBody requestBody = new MultipartBuilder() //建立請求的內容
// .type(MultipartBuilder.FORM)//表單形式
// .addFormDataPart("token", token)//攜帶的參數
// .addFormDataPart("file", file.getName(), RequestBody.create(null, file))//第一個參數是伺服器接收的名稱,第二個是上傳文件的名字,第三個是上傳的文件
// .build();
// Request request = new Request.Builder()//建立請求
// .url(url)//請求的地址
// .post(requestBody)//請求的內容(上面建立的requestBody)
// .build();
try {
OkHttpClient okHttpClient = new OkHttpClient();
MultipartBuilder builder = new MultipartBuilder();
builder.type(MultipartBuilder.FORM);
//追加參數
for (String key : paramsMap.keySet()) {
Object object = paramsMap.get(key);
if (!(object instanceof File)) {
builder.addFormDataPart(key, object.toString());
} else {
File file = (File) object;
builder.addFormDataPart(key, file.getName(), RequestBody.create(null, file));
}
}
//創建RequestBody
RequestBody body = builder.build();
//創建Request
final Request request = new Request.Builder().url(actionUrl).post(body).build();
HLog.v("upLoadFile","upLoadFile",request.urlString());
Call call=okHttpClient.newCall(request);
call.enqueue(callback);
} catch (Exception e) {
Log.e(TAG, e.toString());
}
}
③ OKHttp使用詳解
OkHttp 是一個默認高效的 HTTP 客戶端:
在使用 OkHttp 發送 HTTP 請求時,首先需要獲取一個 OkHttpClient 對象,獲取 OkHttpClient 對象的方式很簡單,在 OkHttp 中大量使用了 Builder 模式。獲取 OkHttpClient 對象的方法如下所示:
GET 請求的執行步驟如下:
POST 請求的構建步驟與 GET 相似,區別是,在構建 Request 對象基基時 在 post() 方法中,設置需轎蔽要發送的數據,發送的數據可為目前流行的 JSON 格式數據,也可以模擬 Form 表單提交的數據,操作如下所示:
構建完 Request 對象後的步驟,就與 GET 請求相似,構建 Call 對象然後,在發送 同步 或 非同步 請求
在 OkHttp 中 進行文件的上傳,是相當簡單的,在發送 POST 請求時,只需要構造一個 MultipartBody 對象即可, MultipartBody 對象可以發送 文件數據,也可以發搏帆謹送基本類型的數據。
OkHttp 作為網路請求工具,簡單且功能強大,並且其大量使用了 構建者模式。
④ Okhttp上傳文件(視頻並攜帶參數)
之前我在csdn上寫過一枝滾篇okhttp上傳圖片頭像的參數解釋:
https://blog.csdn.net/Hu_wenpeng/article/details/105492603
是這樣寫的 因為網路請求 還是retrofit+okhttp
所以請兆搭咐求方法定義成下面這樣:
在這里總結一下 只要和服務能夠通信成功 說明我們寫的方式是沒有錯的,無法是一些參數的問題,不要一看返回非200 就認為自族純己寫的方式有問題
⑤ android怎麼用okhttp封裝網路框架
封裝只是為了能更加簡單,僅此而已~
功能
UI 線程切換
可選擇的Callback(任意選擇UI線程或者子線程)
參數規范化,GET與POST都一樣的傳參方式
上傳/下載進度回調
可以簡單的設置Head部分
可以每次請求時自動加上需要的參數
String/JSON/byte/File… 都能一樣簡單
用法
由於輔助代碼較多,在這里就不一一貼出來了,在這里僅僅演示如何使用。
非同步GET
Http.getAsync("http://wthrcdn.etouch.cn/weather_mini", new UiCallback<String>() {
@Override
public void onFailure(Request request, Response response, Exception e) {
log("getAsync:onFailed");
}
@Override
public void onSuccess(String response, int code) {
log("getAsync:onSuccess:" + response);
}
}, new StrParam("citykey", 101010100)
);123456789101112
由於是 get 請求,在這里參數中的 citykey 會被自動解析到 url 中。
http://wthrcdn.etouch.cn/weather_mini?citykey=1010101001
同步GET
final String url = "http://wthrcdn.etouch.cn/weather_mini?citykey=101010100";
String str = Http.getSync(String.class, url);
log("getSync1:" + str);
str = Http.getSync(url, new ThreadCallback<String>() {
@Override
public void onFailure(Request request, Response response, Exception e) {
log("getSync2:onFailed");
}
@Override
public void onSuccess(String response, int code) {
log("getSync2:onSuccess:" + response);
}
});
log("getSync2:" + str);12345678910111213141516
同步方式支持兩種情況,一種有Callback,一種是沒有。
當然就算加上了Callback也並不是非同步,此時方法會等到執行完成後才會繼續往下走。之所以這么干,是為了方便在callback中直接處理ui的事兒。
在這里有必要說明一下,返回類型需要進行指定,如果沒有Callback哪么需要你傳入返回類型class。
當然如果你傳入了callback,哪么此時class就由callback
Account account = Http.getSync(Account.class, url);
User user = Http.getSync(User.class, url);
String str = Http.getSync(String.class, url, new StrParam("citykey", 101010100));123
Callback 的情況也如上所示。
非同步與同步的區別在於方法名稱:
Http.getSync()
Http.getAsync()
Http.postSync()
Http.postAsync()
Http.uploadSync()
Http.uploadAsync()
Http.downloadSync()
Http.downloadAsync()
默認情況下,upload與download具有callProgress 回調進度功能。
POST
String value1 = "xxx";
String value2 = "xxx";
String url = "http://www..com";
Http.postAsync(url, new HttpCallback<String>() {
@Override
public void onFailure(Request request, Response response, Exception e) {
e.printStackTrace();
}
@Override
public void onSuccess(String response, int code) {
log(response);
}
},
new StrParam("value1", value1),
new StrParam("value2", value2));1234567891011121314151617
post 的請求方法與get基本如出一轍。
Upload
File file = getAssetsFile();
Http.uploadAsync("http://img.hoop8.com/upload.php", "uploadimg", file, new UiCallback<String>() {
@Override
public void onProgress(long current, long count) {
super.onProgress(current, count);
log("uploadAsync onProgress:" + current + "/" + count);
mUpload.setProgress((int) ((current * 100.00 / count)));
}
@Override
public void onFailure(Request request, Response response, Exception e) {
e.printStackTrace();
log("uploadAsync onFailed");
}
@Override
public void onSuccess(String response, int code) {
log("uploadAsync onSuccess:" + response);
}
});
上傳部分也很簡單,如果需要帶有參數哪么和Post的使用方式一樣。當然此時傳入參數就不是 StrParam 而是 IOParam.
上傳的時候你可以僅僅傳遞文件+文件對應的name;或者 傳遞 IOParam; 也可以 StrParam+IOParam的方式;當然終極一點你可以傳遞:Param 類型。
⑥ 如何高效的使用Okhttp
OkHttp 是一個在開發可汗學院Android APP過程中非常重要的依賴庫。它的默認的配置為我們提供了非常重要實用功能,下面一些步驟我們可以讓Okhttp提供更多功能使用靈活和內省能力。
1. 啟用文件系統上的響應緩存
默認情況下,Okhttp不支持響應緩存,包括HTTP Cache-Control頭允許緩存響應。因此,客戶端通過一次又一次的請求相同的資源浪費時間和帶寬。而不是簡單地讀取初始響應後緩存的副本。
要在文件系統中啟用響應緩存,需要配置com.squareup.okhttp.Cache實例,並把它傳遞給你的OkHttpClient實例的setCache方法。你必須初始化緩存與存放目錄的文件,並以位元組為單位的最大值。
響應返回數據可以寫入給定目錄文件,如果一個響應的緩存超過了給定的大小。我們可以採取 LRU policy 。
我們可以在 stackoverflow 查看 Jesse Wilson 的回復。我們可以通過context.getCacheDir()在子目錄中緩存我們的響應:
// Base directory recommended by http://stackoverflow.com/a/32752861/400717.
// Guard against null, which is possible according to
// https://groups.google.com/d/msg/android-developers/-694j87eXVU/YYs4b6kextwJ and
// http://stackoverflow.com/q/4441849/400717.
final @Nullable File baseDir = context.getCacheDir();
if (baseDir != null) {
final File cacheDir = new File(baseDir, "HttpResponseCache");
okHttpClient.setCache(new Cache(cacheDir, HTTP_RESPONSE_DISK_CACHE_MAX_SIZE));
}
// Base directory recommended by http://stackoverflow.com/a/32752861/400717.
// Guard against null, which is possible according to
// https://groups.google.com/d/msg/android-developers/-694j87eXVU/YYs4b6kextwJ and
// http://stackoverflow.com/q/4441849/400717.
final @NullableFilebaseDir = context.getCacheDir();
if (baseDir != null) {
final FilecacheDir = new File(baseDir, "HttpResponseCache");
okHttpClient.setCache(new Cache(cacheDir, HTTP_RESPONSE_DISK_CACHE_MAX_SIZE));
}
在可汗學院的程序中我們指定 HTTP_RESPONSE_DISK_CACHE_MAX_SIZE as 10 * 1024 * 1024 , or 10 MB的大小
2. 集成Stetho
Stetho 是Facebook的一個可愛的庫,可以使用Chrome瀏覽器的Chrome開發人員工具功能來檢查你的Andr oid應用程序。
Stetho除了允許你檢查你的應用程序的SQLite資料庫,還可以查看View的層次結構。允許你檢查由OkHttp發起的每個請求和響應:
這種自省機制是確保伺服器返回允許資源緩存的HTTP頭是非常有用的,以及驗證沒有請求時,保證緩存的資源存在。
要想使用Stetho,只需添加一個StethoInterceptor實例的網路攔截器列表:
okHttpClient.networkInterceptors().add(new StethoInterceptor());
okHttpClient.networkInterceptors().add(new StethoInterceptor());
然後,運行應用程序,打開瀏覽器後,輸入chrome://inspect。然後你就會看到應用程序的設備和標識符的列表。然後滑鼠右鍵選擇inspect 打開開發者工具,然後打開新的tab,開始監控OkHttp請求。
3. 使用Picasso 和 Retrofit
你可能使用過 Picasso 來載入網路圖片,或者使用 Retrofit 來簡化發出請求和解碼響應。這些第三方庫將隱式地創建自己的OkHttpClient供內部使用,如果你不明確指定一個。
Picasso version 2.5.2的OkHttpDownloader類:
private static OkHttpClient defaultOkHttpClient() {
OkHttpClient client = new OkHttpClient();
client.setConnectTimeout(Utils.DEFAULT_CONNECT_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
client.setReadTimeout(Utils.DEFAULT_READ_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
client.setWriteTimeout(Utils.DEFAULT_WRITE_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
return client;
}
private static () {
OkHttpClientclient = new OkHttpClient();
client.setConnectTimeout(Utils.DEFAULT_CONNECT_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
client.setReadTimeout(Utils.DEFAULT_READ_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
client.setWriteTimeout(Utils.DEFAULT_WRITE_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
return client;
}
Retrofit也有類似的工廠方法來創建自己的OkHttpClient。
圖片一般在應用程序中需要載入的比較大的資源。盡管Picasso自己維護它的LRU機制來緩存圖片,在內存中嚴格執行。如果客戶端嘗試使用Picasso來載入圖片。Picasso會找不到其在內存中緩存圖像,然後將委託載入該圖片到它的內部OkHttpClient實例。並且默認情況下該實例將始終從伺服器載入圖片資源。
作為defaultOkHttpClient的方法不能與上面提到的文件系統中的響應緩存配置結合起來。
指定你自己的OkHttpClient實例允許返回數據從文件系統緩存響應,圖片不會從伺服器載入。這是非常重要的在程序第一次啟動以後。這個時候Picasso的內存緩存是冷的。所以它會頻繁的委託OkHttpClient實例去載入圖片。
這就需要構建配置了您Picasso 的OkHttpClient實例,如果你在你的代碼中使用
Picasso.with(context).load(...)
Picasso.with(context).load(...)
載入圖片,你是用的是Picasso的單例模式。這是通過with方法懶漢模式地實例化並配置自己的OkHttpClient。因此,我們必須使我們自己的Picasso實例在單例之前通過wiht方法調用。
實現這個,可以簡單的將OkHttpClient實例封裝在OkHttpDownloader中,然後傳遞給 Picasso.Builder 實例的downloader方法。
final Picasso picasso = new Picasso.Builder(context)
.downloader(new OkHttpDownloader(okHttpClient))
.build();
// The client should inject this instance whenever it is needed, but replace the singleton
// instance just in case.
Picasso.setSingletonInstance(picasso);
final Picassopicasso = new Picasso.Builder(context)
.downloader(new OkHttpDownloader(okHttpClient))
.build();
// The client should inject this instance whenever it is needed, but replace the singleton
// instance just in case.
Picasso.setSingletonInstance(picasso);
在Retrofit中要使用OkHttpClient實例,需要改造1.9.x的一個RestAdapter,需要將OkHttpClient封裝OkClient的實例中。然後把它傳遞給RestAdapter.Builder實例的setClient方法。
restAdapterBuilder.setClient(new OkClient(httpClient));
restAdapterBuilder.setClient(new OkClient(httpClient));
在 Retrofit 2.0中只需要簡單的將OkHttpClient傳遞給Retrofit.Builder實例的client方法。
在可汗學院的APP中我們通過 Dagger 依賴注入來確保我們只有一個OkHttpClient的實例。這種方法同樣也適用於Picasso和Retrofit我們提供了一個為OkHttpClient實例提供單例模式的註解示例:
@Provides
@Singleton
public OkHttpClient okHttpClient(final Context context, ...) {
final OkHttpClient okHttpClient = new OkHttpClient();
configureClient(okHttpClient, ...);
return okHttpClient;
}
@Provides
@Singleton
public OkHttpClientokHttpClient(final Contextcontext, ...) {
final OkHttpClientokHttpClient = new OkHttpClient();
configureClient(okHttpClient, ...);
return okHttpClient;
}
OkHttpClient將會通過Dagger的註解創建一個實例提供給我們的Picasso和Retrofit。
4.指定一個用戶代理攔截器
日誌文件和分析為我們提供了更多有用的信息,當客戶在每個請求提供詳細的User-Agent
header值的時候。默認情況下,Okhttp包含User-Agent值只有在特定的Okhttp版本中。為了指定我們自己的user
agent。首先創建攔截器的替換值, 我們可以看stackoverflow的建議 。
public final class UserAgentInterceptor implements Interceptor {
private static final String USER_AGENT_HEADER_NAME = "User-Agent";
private final String userAgentHeaderValue;
public UserAgentInterceptor(String userAgentHeaderValue) {
this.userAgentHeaderValue = Preconditions.checkNotNull(userAgentHeaderValue);
}
@Override
public Response intercept(Chain chain) throws IOException {
final Request originalRequest = chain.request();
final Request requestWithUserAgent = originalRequest.newBuilder()
.removeHeader(USER_AGENT_HEADER_NAME)
.addHeader(USER_AGENT_HEADER_NAME, userAgentHeaderValue)
.build();
return chain.proceed(requestWithUserAgent);
}
}
public final class UserAgentInterceptor implements Interceptor {
private static final String USER_AGENT_HEADER_NAME = "User-Agent";
private final String userAgentHeaderValue;
public UserAgentInterceptor(String userAgentHeaderValue) {
this.userAgentHeaderValue = Preconditions.checkNotNull(userAgentHeaderValue);
}
@Override
public Responseintercept(Chainchain) throws IOException {
final RequestoriginalRequest = chain.request();
final RequestrequestWithUserAgent = originalRequest.newBuilder()
.removeHeader(USER_AGENT_HEADER_NAME)
.addHeader(USER_AGENT_HEADER_NAME, userAgentHeaderValue)
.build();
return chain.proceed(requestWithUserAgent);
}
}
為了創建User-Agent header值人然後傳遞給UserAgentInterceptor的構造器,使用你得到的任何信息。
我們可以使用:
android 的系統信息可以清晰的傳遞出這是一台android 設備
Build.MODEL 或者「製造商提供的用戶可見最終可見的名稱」
Build.BRAND或者「消費者可見的品牌與產品/硬體相關信息」
Build.VERSION.SDK_INT或者「消費者可見的Android提供的SDK版本號」
BuildConfig.APPLICATION_ID
BuildConfig.VERSION_NAME
BuildConfig.VERSION_CODE
最後三個值由的applicationID,VERSIONCODE和VERSIONNAME的值在我們的Gradle build腳本中
了解更多信息可以查看 versioning your applications 和 configuring your applicationId with Gradle
請注意,如果您的應用程序使用的是WebView,您可以配置使用相同的 User-Agent header值,你可以通過下面方法創建UserAgentInterceptor:
WebSettings settings = webView.getSettings();
settings.setUserAgentString(userAgentHeaderValue);
WebSettingssettings = webView.getSettings();
settings.setUserAgentString(userAgentHeaderValue);
5.指定合理的超時
2.5.0版本之前,OkHttp請求默認為永不超時。2.5.0版本開始如果建立連接請求超時,如果從連接讀取下一個位元組或寫入的下一個位元組到連接,花費超過10秒,就終止。這樣做需要更新到2.5.0版本我們就不需要在我們的代碼中修改bug。原因很簡單是我因為我們第一次使用的時候使用了錯誤的路徑。
要覆蓋這些默認值,可以分別調用setConnectTimeout,setReadTimeout或setWriteTimeout。
需要注意的是Picasso和Retrofit為OkHttpClient實例指定不同的超時值時,默認情況下,Picasso指定:
連接超過15秒.
讀取超過20秒
寫入超過20秒
而Retrofit指定:
連接超過15秒.
讀取超過20秒
沒有寫入超時
通過配置Picasso和Retrofit自己的OkHttpClient實例你可以確保所有的請求超時是一致的
⑦ Android Q 上基於 OkHttp 上傳(大)文件的實現
如圖,RequestBody 有好幾個 create 方法,可以滿足不同場景下的內容上傳,比如字元串、位元組數組和文件。
顯然,字元串和位元組數組是不能上傳大文件的,均可能 OOM。
那麼,就只能使用 RequestBody create(MediaType contentType, File file) 方法了。正常情況下也是沒什麼問題的,但是在 Android Q 上,由於存儲許可權的變更,將導致無法直接訪問從內容庫所選擇的文件。
得到如下日誌:
可見,即使通過 uri 得到了文件的真實路徑,也是無法直接訪問的。
通過上面的實驗可以看到,我們是無法直接通過 File 相關的 API 訪問原始文件的,但是我們卻可以通過 ContentResolver 得到原始文件的流。
類似地,可以基於流或者 FileDescriptor 對圖片解碼成 Bitmap,參考:
⑧ OkHttp3上傳file文件和其他參數,怎麼上傳
里的電腦一玩
⑨ Okhttp 使用詳解
一個最簡單的OkHttpClient
一個復雜點的OkHttpClient配置
具體可配置參數見OkHttpClient.Builder類,幾點注意事項:
兩種攔截器的區別
官方提供的Logging Interceptor
地址: https://github.com/victorfan336/okhttp-logging-interceptor
gradle.build中添加依賴:
compile 'com.squareup.okhttp3:logging-interceptor:3.1.2'
通過Request.Builder創建請求,默認是Get請求
主要是構建RequestBody,並設置Content-Type消息頭洞擾。
1.普通Post請求
比如json請求
2. 使用FormBody傳遞鍵值對參數
Content-Type: application/x-www-form-urlencoded
比如:
3. 使用RequestBody傳遞Json或File對象
4. 使用MultipartBody同時傳遞鍵值對參數和File對象
5. 使用MultipartBody提交分塊請求
6. 自定義RequestBody實現流的上傳
1、同步執行
由於android強制要求網路請納段旦求在線程中執行,所以無法使用execute
2、非同步執行
1. 設置請求頭
2. 設置超時
3. 設置緩存
1、對於Get請求,如果請求參數較多,自己拼接Url較為麻煩
比如
拼接結果: http://www..com/user/login/username=zhangsan&password=123456
如果能做一燃褲些封裝,直接addParam(key,value)的形式則會簡單很多。
2、Callback在子線程中回調,大部分時候,我們都是需要更新UI的,還需自己post到主線程中處理。
3、構建請求步驟比較多
因此,Square提供了針對OkHttp的封裝庫Retrofit,另外Github上也有很多第三方的封裝庫,比如OkGo。
⑩ Okhttp 使用(同步、非同步/get、post/上傳文件)
目前Android端調用網路請求最常用的框架就是OKHttp,目前項目中也經常會用到。OKHTTP有哪些特點呢?下面是官網給出的OKHTTP的特點:
官網地址: https://square.github.io/okhttp/
想要詳細了解HTTP/2,可以參考: https://www.jianshu.com/p/828a29bced9f
接下來就可以愉快的開始使用OKhttp進行開發了。
OKhttpclient通過builder構建,構建的時候涉及到很多配置項,本次簡單對其中一些配置項做了說明,後續會對一些重要的配置項做專題說明正察。在實際的項目中的配置項根據項目具體需求進行配置。
上述配置項中比較常用的有
同步get請求會阻塞當前線程直到返回舉枝茄結果,請求大致分為四個步驟:
非同步請求方式的步驟和上述前兩個步驟基本搭拍一致,主要發起請求的方式發生了變化,結果通過回調返回。這種請求方式對請求的線程沒有限制。
與get請求方式不同的是post請求需要構建RequestBody,在請求時攜帶RequestBody。