Это не совсем вопрос, однако я хотел бы поделиться здесь некоторыми из моего рабочего кода для справки, когда вам это нужно.
Как мы знаем, HttpEntity
это устарело в API22 и полностью удалено с API23. На данный момент мы больше не можем получить доступ к HttpEntity Reference в Android Developer (404). Итак, ниже приведен мой рабочий пример кода для многостраничного запроса POST с Volley и без HttpEntity . Работает, проверено с помощью Asp.Net Web API
. Конечно, код, возможно, является всего лишь базовым образцом, который публикует два существующих файла с возможностью рисования, также это не лучшее решение для всех случаев и плохая настройка.
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);
}
}
ОБНОВИТЬ:
Для текстовой части, пожалуйста, обратитесь к ответу @Oscar ниже.
Ответы:
Я перепишу ваш код @RacZo и @BNK более модульным и простым в использовании, например
Проверьте полный код
VolleyMultipartRequest
на мою суть .источник
Просто хочу добавить к ответу. Я пытался понять, как добавить текстовые поля в тело, и для этого создал следующую функцию:
Работает очень хорошо.
источник
Для тех, кто изо всех сил пытается отправить параметры utf-8 и все еще не везет, проблема, с которой я столкнулся, была в dataOutputStream, и измените код @RacZo на код ниже:
источник
Вот Kotlin-версия класса, позволяющая выполнять составные запросы с помощью Volley 1.1.1.
В основном он основан на решении @BNK, но немного упрощен. Особых проблем с производительностью не заметил. Я загрузил картинку размером 5 Мб примерно за 3 секунды.
источник
Я нашел обертку исходной библиотеки volley, которую легче интегрировать для многостраничных запросов. Он также поддерживает загрузку составных данных вместе с другими параметрами запроса. Следовательно, я делюсь своим кодом для будущих разработчиков, которые могут столкнуться с проблемой, с которой я столкнулся (например, загрузка составных данных с помощью залпа вместе с некоторыми другими параметрами).
Добавьте в
build.gradle
файл следующую библиотеку .Обратите внимание, что я удалил исходную библиотеку Volley из своей
build.gradle
и использовал вместо нее указанную выше, которая может обрабатывать как многостраничные, так и обычные запросы с аналогичной техникой интеграции.Затем мне просто нужно было написать следующий класс, который обрабатывает операцию запроса POST.
Теперь выполните следующую задачу.
С помощью этой библиотеки вы можете загружать по одному файлу за раз. Однако мне удалось загрузить несколько файлов, просто запустив несколько задач.
Надеюсь, это поможет!
источник