使用OKhttp在Android中的multipart中上传单个大文件(更具体地说,到s3)有哪些选择?
答案 0 :(得分:32)
从OkHttp Recipes page开始,此代码会将图片上传到Imgur:
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());
}
你需要将它改编为S3,但你需要的类应该是相同的。
答案 1 :(得分:30)
获取OkHttp 2.1,并使用MultipartBuilder.addFormDataPart()
,它将文件名作为参数。
/**
* Upload Image
*
* @param memberId
* @param sourceImageFile
* @return
*/
public static JSONObject uploadImage(String memberId, String sourceImageFile) {
try {
File sourceFile = new File(sourceImageFile);
Log.d(TAG, "File...::::" + sourceFile + " : " + sourceFile.exists());
final MediaType MEDIA_TYPE = sourceImageFile.endsWith("png") ?
MediaType.parse("image/png") : MediaType.parse("image/jpeg");
RequestBody requestBody = new MultipartBuilder()
.type(MultipartBuilder.FORM)
.addFormDataPart("member_id", memberId)
.addFormDataPart("file", "profile.png", RequestBody.create(MEDIA_TYPE_PNG, sourceFile))
.build();
Request request = new Request.Builder()
.url(URL_UPLOAD_IMAGE)
.post(requestBody)
.build();
OkHttpClient client = new OkHttpClient();
Response response = client.newCall(request).execute();
return new JSONObject(response.body().string());
} catch (UnknownHostException | UnsupportedEncodingException e) {
Log.e(TAG, "Error: " + e.getLocalizedMessage());
} catch (Exception e) {
Log.e(TAG, "Other Error: " + e.getLocalizedMessage());
}
return null;
}
compile 'com.squareup.okhttp3:okhttp:3.4.1'
RequestBody 替换为:
RequestBody requestBody = new MultipartBody.Builder()
.setType(MultipartBody.FORM)
.addFormDataPart("uploaded_file", filename, RequestBody.create(MEDIA_TYPE_PNG, sourceFile))
.addFormDataPart("result", "my_image")
.build();
答案 2 :(得分:2)
for okhttp 2.6.0 {
try {
File file = new File(Environment.getExternalStorageDirectory().getPath()+"/xxx/share/" + "ic_launcher.png");
String contentType = file.toURL().openConnection().getContentType();
RequestBody fileBody = RequestBody.create(MediaType.parse(contentType), file);
RequestBody requestBody = new MultipartBuilder()
.type(MultipartBuilder.FORM)
.addFormDataPart("fileUploadType","1")
.addFormDataPart("miniType",contentType)
.addFormDataPart("ext",file.getAbsolutePath().substring(file.getAbsolutePath().lastIndexOf(".")))
.addFormDataPart("fileTypeName","img")
.addFormDataPart("Filedata","ss.png",fileBody)
.build();
Request request = new Request.Builder()
.url(Contains.MULTIPARTY_POST)
.post(requestBody)
.build();
okHttpClient.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Request request, IOException e) {
runOnUiThread(new Runnable() {
@Override
public void run() {
tvGetNews.setText("upload fail");
}
});
}
@Override
public void onResponse(Response response) throws IOException {
runOnUiThread(new Runnable() {
@Override
public void run() {
tvGetNews.setText("upload success");
}
});
}
});
} catch (IOException e) {
e.printStackTrace();
}
}
答案 3 :(得分:0)
对于okhttp 4. *,请使用MultipartBody.Builder
:
fun postMultipart(url: String, text: String, imagePath: String, imageFileName: String): okhttp3.Response? {
val file = File(imagePath)
val fileRequestBody = file.asRequestBody("image/jpeg".toMediaType())
val requestBody = MultipartBody.Builder()
.addFormDataPart("text", text)
.addFormDataPart("image", imageFileName, fileRequestBody)
.build()
val request = getRequestBuilder(url)
.post(requestBody)
.build()
val client = OkHttpClient()
client.newCall(request).execute().use { response ->
return response
}
}
答案 4 :(得分:0)
在 Android 中,您通常会与 Uri
分开。使用大文件时的问题是,如果您尝试将完整流读取到字节数组(内存中的所有内容)或最终使用 Uri 流创建无用文件,则很容易遇到 OutOfMemoryError
。这是因为 RequestBody
不支持从 Stream
创建(因为有时 OkHttp 需要多次读取它,例如如果您获得 30X 重定向)或 Uri
(因为 OkHttp 不是一个 Android 库)。
但是 OkHttp 提供了库 Okio,具有方便的类模拟流(Source
和 Sink
)和更方便的内部使用。
因此,要创建一个 BodyRequest
形式的 Uri
避免任何 OutOfMemoryError
由于大文件创建它:
private static final MediaType MULTIPART_FOR_DATA = MediaType.parse("multipart/form-data");
private @NotNull RequestBody getFilePart(Uri largeFileUri) {
return new RequestBody() {
@Override
public MediaType contentType() {
return MULTIPART_FOR_DATA;
}
@Override
public void writeTo(@NotNull BufferedSink sink) throws IOException {
try (Source source = Okio.source(context.getContentResolver().openInputStream(mediaUri))) {
sink.writeAll(source);
}
}
};
}
感谢在以下 GitHub 主题 https://github.com/square/okhttp/issues/3585
中发帖和评论的所有人