Ini sebenarnya bukan pertanyaan, namun, saya ingin membagikan beberapa kode kerja saya di sini untuk referensi Anda saat Anda membutuhkannya.
Seperti yang kita ketahui, itu HttpEntity
sudah usang dari API22 dan benar-benar dihapus sejak API23. Saat ini, kami tidak dapat mengakses Referensi HttpEntity di Pengembang Android lagi (404). Jadi, berikut ini adalah kode contoh kerja saya untuk Permintaan Multipart POST dengan Volley dan tanpa HttpEntity . Ini bekerja, diuji dengan Asp.Net Web API
. Tentu saja, kode tersebut mungkin hanya contoh dasar yang memposting dua file drawable yang ada, juga bukan solusi terbaik untuk semua kasus, dan bukan penyetelan yang baik.
MultipartActivity.java:
package com.example.multipartvolley;
import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.support.v4.content.ContextCompat;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.Toast;
import com.android.volley.NetworkResponse;
import com.android.volley.Response;
import com.android.volley.VolleyError;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;
public class MultipartActivity extends Activity {
private final Context context = this;
private final String twoHyphens = "--";
private final String lineEnd = "\r\n";
private final String boundary = "apiclient-" + System.currentTimeMillis();
private final String mimeType = "multipart/form-data;boundary=" + boundary;
private byte[] multipartBody;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_multipart);
byte[] fileData1 = getFileDataFromDrawable(context, R.drawable.ic_action_android);
byte[] fileData2 = getFileDataFromDrawable(context, R.drawable.ic_action_book);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream(bos);
try {
// the first file
buildPart(dos, fileData1, "ic_action_android.png");
// the second file
buildPart(dos, fileData2, "ic_action_book.png");
// send multipart form data necesssary after file data
dos.writeBytes(twoHyphens + boundary + twoHyphens + lineEnd);
// pass to multipart body
multipartBody = bos.toByteArray();
} catch (IOException e) {
e.printStackTrace();
}
String url = "http://192.168.1.100/api/postfile";
MultipartRequest multipartRequest = new MultipartRequest(url, null, mimeType, multipartBody, new Response.Listener<NetworkResponse>() {
@Override
public void onResponse(NetworkResponse response) {
Toast.makeText(context, "Upload successfully!", Toast.LENGTH_SHORT).show();
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
Toast.makeText(context, "Upload failed!\r\n" + error.toString(), Toast.LENGTH_SHORT).show();
}
});
VolleySingleton.getInstance(context).addToRequestQueue(multipartRequest);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_multipart, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
private void buildPart(DataOutputStream dataOutputStream, byte[] fileData, String fileName) throws IOException {
dataOutputStream.writeBytes(twoHyphens + boundary + lineEnd);
dataOutputStream.writeBytes("Content-Disposition: form-data; name=\"uploaded_file\"; filename=\""
+ fileName + "\"" + lineEnd);
dataOutputStream.writeBytes(lineEnd);
ByteArrayInputStream fileInputStream = new ByteArrayInputStream(fileData);
int bytesAvailable = fileInputStream.available();
int maxBufferSize = 1024 * 1024;
int bufferSize = Math.min(bytesAvailable, maxBufferSize);
byte[] buffer = new byte[bufferSize];
// read file and write it into form...
int bytesRead = fileInputStream.read(buffer, 0, bufferSize);
while (bytesRead > 0) {
dataOutputStream.write(buffer, 0, bufferSize);
bytesAvailable = fileInputStream.available();
bufferSize = Math.min(bytesAvailable, maxBufferSize);
bytesRead = fileInputStream.read(buffer, 0, bufferSize);
}
dataOutputStream.writeBytes(lineEnd);
}
private byte[] getFileDataFromDrawable(Context context, int id) {
Drawable drawable = ContextCompat.getDrawable(context, id);
Bitmap bitmap = ((BitmapDrawable) drawable).getBitmap();
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.PNG, 0, byteArrayOutputStream);
return byteArrayOutputStream.toByteArray();
}
}
MultipartRequest.java:
package com.example.multipartvolley;
import com.android.volley.AuthFailureError;
import com.android.volley.NetworkResponse;
import com.android.volley.ParseError;
import com.android.volley.Request;
import com.android.volley.Response;
import com.android.volley.VolleyError;
import com.android.volley.toolbox.HttpHeaderParser;
import java.util.Map;
class MultipartRequest extends Request<NetworkResponse> {
private final Response.Listener<NetworkResponse> mListener;
private final Response.ErrorListener mErrorListener;
private final Map<String, String> mHeaders;
private final String mMimeType;
private final byte[] mMultipartBody;
public MultipartRequest(String url, Map<String, String> headers, String mimeType, byte[] multipartBody, Response.Listener<NetworkResponse> listener, Response.ErrorListener errorListener) {
super(Method.POST, url, errorListener);
this.mListener = listener;
this.mErrorListener = errorListener;
this.mHeaders = headers;
this.mMimeType = mimeType;
this.mMultipartBody = multipartBody;
}
@Override
public Map<String, String> getHeaders() throws AuthFailureError {
return (mHeaders != null) ? mHeaders : super.getHeaders();
}
@Override
public String getBodyContentType() {
return mMimeType;
}
@Override
public byte[] getBody() throws AuthFailureError {
return mMultipartBody;
}
@Override
protected Response<NetworkResponse> parseNetworkResponse(NetworkResponse response) {
try {
return Response.success(
response,
HttpHeaderParser.parseCacheHeaders(response));
} catch (Exception e) {
return Response.error(new ParseError(e));
}
}
@Override
protected void deliverResponse(NetworkResponse response) {
mListener.onResponse(response);
}
@Override
public void deliverError(VolleyError error) {
mErrorListener.onErrorResponse(error);
}
}
MEMPERBARUI:
Untuk bagian teks, lihat jawaban @ Oscar di bawah ini.
Jawaban:
Saya menulis ulang kode Anda @RacZo dan @BNK lebih modular dan mudah digunakan seperti
Periksa kode lengkap
VolleyMultipartRequest
di intisari saya .sumber
Hanya ingin menambah jawabannya. Saya mencoba mencari cara untuk menambahkan bidang teks ke tubuh dan membuat fungsi berikut untuk melakukannya:
Ini bekerja dengan cukup baik.
sumber
Bagi mereka yang kesulitan mengirim parameter utf-8 dan masih belum berhasil, masalah yang saya alami ada di dataOutputStream, dan ubah kode @RacZo menjadi kode di bawah ini:
sumber
Berikut adalah versi Kotlin dari kelas yang mengizinkan permintaan multi bagian dengan Volley 1.1.1.
Ini sebagian besar didasarkan pada solusi @ BNK tetapi sedikit disederhanakan. Saya tidak melihat adanya masalah kinerja tertentu. Saya mengunggah foto 5Mb dalam waktu sekitar 3 detik.
sumber
Saya menemukan pembungkus perpustakaan voli asli yang lebih mudah diintegrasikan untuk permintaan multi-bagian. Ini juga mendukung pengunggahan data multi-bagian bersama dengan parameter permintaan lainnya. Oleh karena itu saya membagikan kode saya untuk pengembang masa depan yang mungkin mengalami masalah yang saya alami (yaitu mengunggah data multi-bagian menggunakan voli bersama dengan beberapa parameter lainnya).
Tambahkan pustaka berikut di
build.gradle
file.Harap dicatat bahwa, saya menghapus perpustakaan voli asli dari perpustakaan saya
build.gradle
dan menggunakan perpustakaan di atas sebagai gantinya yang dapat menangani permintaan multi-bagian dan normal yang memiliki teknik integrasi serupa.Kemudian saya hanya perlu menulis kelas berikut yang menangani operasi permintaan POST.
Sekarang jalankan tugas seperti berikut.
Anda dapat mengupload file satu per satu menggunakan perpustakaan ini. Namun, saya dapat mengunggah banyak file, hanya dengan memulai banyak tugas.
Semoga membantu!
sumber