Post Multipart Request With Android Sdk

Post multipart request with Android SDK

Update April 29th 2014:

My answer is kind of old by now and I guess you rather want to use some kind of high level library such as Retrofit.


Based on this blog I came up with the following solution:
http://blog.tacticalnuclearstrike.com/2010/01/using-multipartentity-in-android-applications/

You will have to download additional libraries to get MultipartEntity running!

1) Download httpcomponents-client-4.1.zip from http://james.apache.org/download.cgi#Apache_Mime4J and add apache-mime4j-0.6.1.jar to your project.

2) Download httpcomponents-client-4.1-bin.zip from http://hc.apache.org/downloads.cgi and add httpclient-4.1.jar, httpcore-4.1.jar and httpmime-4.1.jar to your project.

3) Use the example code below.

private DefaultHttpClient mHttpClient;


public ServerCommunication() {
HttpParams params = new BasicHttpParams();
params.setParameter(CoreProtocolPNames.PROTOCOL_VERSION, HttpVersion.HTTP_1_1);
mHttpClient = new DefaultHttpClient(params);
}


public void uploadUserPhoto(File image) {

try {

HttpPost httppost = new HttpPost("some url");

MultipartEntity multipartEntity = new MultipartEntity(HttpMultipartMode.BROWSER_COMPATIBLE);
multipartEntity.addPart("Title", new StringBody("Title"));
multipartEntity.addPart("Nick", new StringBody("Nick"));
multipartEntity.addPart("Email", new StringBody("Email"));
multipartEntity.addPart("Description", new StringBody(Settings.SHARE.TEXT));
multipartEntity.addPart("Image", new FileBody(image));
httppost.setEntity(multipartEntity);

mHttpClient.execute(httppost, new PhotoUploadResponseHandler());

} catch (Exception e) {
Log.e(ServerCommunication.class.getName(), e.getLocalizedMessage(), e);
}
}

private class PhotoUploadResponseHandler implements ResponseHandler<Object> {

@Override
public Object handleResponse(HttpResponse response)
throws ClientProtocolException, IOException {

HttpEntity r_entity = response.getEntity();
String responseString = EntityUtils.toString(r_entity);
Log.d("UPLOAD", responseString);

return null;
}

}

POST Multipart Form Data using Retrofit 2.0 including image

I am highlighting the solution in both 1.9 and 2.0 since it is useful for some

In 1.9, I think the better solution is to save the file to disk and use it as Typed file like:

RetroFit 1.9

(I don't know about your server-side implementation) have an API interface method similar to this

@POST("/en/Api/Results/UploadFile")
void UploadFile(@Part("file") TypedFile file,
@Part("folder") String folder,
Callback<Response> callback);

And use it like

TypedFile file = new TypedFile("multipart/form-data",
new File(path));

For RetroFit 2 Use the following method

RetroFit 2.0 ( This was a workaround for an issue in RetroFit 2 which is fixed now, for the correct method refer jimmy0251's answer)

API Interface:

public interface ApiInterface {

@Multipart
@POST("/api/Accounts/editaccount")
Call<User> editUser(@Header("Authorization") String authorization,
@Part("file\"; filename=\"pp.png\" ") RequestBody file,
@Part("FirstName") RequestBody fname,
@Part("Id") RequestBody id);
}

Use it like:

File file = new File(imageUri.getPath());

RequestBody fbody = RequestBody.create(MediaType.parse("image/*"),
file);

RequestBody name = RequestBody.create(MediaType.parse("text/plain"),
firstNameField.getText()
.toString());

RequestBody id = RequestBody.create(MediaType.parse("text/plain"),
AZUtils.getUserId(this));

Call<User> call = client.editUser(AZUtils.getToken(this),
fbody,
name,
id);

call.enqueue(new Callback<User>() {

@Override
public void onResponse(retrofit.Response<User> response,
Retrofit retrofit) {

AZUtils.printObject(response.body());
}

@Override
public void onFailure(Throwable t) {

t.printStackTrace();
}
});

How to send a “multipart/form-data” POST in Android with Volley

I might be wrong on this but I think you need to implement your own com.android.volley.toolbox.HttpStack for this because the default ones (HurlStack if version > Gingerbread or HttpClientStack) don't deal with multipart/form-data.

Edit:

And indeed I was wrong. I was able to do it using MultipartEntity in Request like this:

public class MultipartRequest extends Request<String> {

private MultipartEntity entity = new MultipartEntity();

private static final String FILE_PART_NAME = "file";
private static final String STRING_PART_NAME = "text";

private final Response.Listener<String> mListener;
private final File mFilePart;
private final String mStringPart;

public MultipartRequest(String url, Response.ErrorListener errorListener, Response.Listener<String> listener, File file, String stringPart)
{
super(Method.POST, url, errorListener);

mListener = listener;
mFilePart = file;
mStringPart = stringPart;
buildMultipartEntity();
}

private void buildMultipartEntity()
{
entity.addPart(FILE_PART_NAME, new FileBody(mFilePart));
try
{
entity.addPart(STRING_PART_NAME, new StringBody(mStringPart));
}
catch (UnsupportedEncodingException e)
{
VolleyLog.e("UnsupportedEncodingException");
}
}

@Override
public String getBodyContentType()
{
return entity.getContentType().getValue();
}

@Override
public byte[] getBody() throws AuthFailureError
{
ByteArrayOutputStream bos = new ByteArrayOutputStream();
try
{
entity.writeTo(bos);
}
catch (IOException e)
{
VolleyLog.e("IOException writing to ByteArrayOutputStream");
}
return bos.toByteArray();
}

@Override
protected Response<String> parseNetworkResponse(NetworkResponse response)
{
return Response.success("Uploaded", getCacheEntry());
}

@Override
protected void deliverResponse(String response)
{
mListener.onResponse(response);
}
}

It's pretty raw but I tried it with an image and a simple string and it works. The response is a placeholder, doesn't make much sense to return a Response String in this case. I had problems using apache httpmime to use MultipartEntity so I used this https://code.google.com/p/httpclientandroidlib/ don't know if there's a better way.
Hope it helps.

Edit

You can use httpmime without using httpclientandroidlib, the only dependency is httpcore.

How to post a multi part form data from android to web api?

There are many post about multipart on stackoverflow,try this

public static String uploadMultipartFile(String root, String token,
String username, String sourceFileUri,
String fileStyle)
{
HttpURLConnection connection = null;
DataOutputStream outputStream = null;
String pathToOurFile = sourceFileUri;
String lineEnd = "\r\n";
String twoHyphens = "--";
String boundary = "*****";
StringBuffer response = new StringBuffer();
try
{
FileInputStream fileInputStream = new FileInputStream(new File(pathToOurFile));
URL url = new URL(root);
connection = (HttpURLConnection) url.openConnection();

if (token != null)
{
connection.setRequestProperty("Authorization", "Basic " + token);
}
if (username != null)
{
connection.setRequestProperty("Username", username);
}
if (fileStyle != null)
{
connection.setRequestProperty("file-type", fileStyle);
}

String fileExtension = FilenameUtils.getExtension(sourceFileUri);
String mime = Utils.getFileMIME(fileExtension);

Log.d("uploadMultipartFile","fileExtension:"+fileExtension+",mime:"+mime);

connection.setDoInput(true);
connection.setDoOutput(true);
connection.setUseCaches(false);

connection.setRequestMethod("POST");
connection.setRequestProperty("Connection", "Keep-Alive");
connection.setRequestProperty("Cache-Control", "no-cache");
connection.setRequestProperty("User-Agent", "CodeJava Agent");
connection.setRequestProperty("Content-Type", "multipart/form-data;boundary=" + boundary);

outputStream = new DataOutputStream(connection.getOutputStream());
outputStream.writeBytes(twoHyphens + boundary + lineEnd);
outputStream.writeBytes("Content-Disposition: form-data; name=\"uploadedfile\";filename=\""
+ pathToOurFile + "\"" + lineEnd);
outputStream.writeBytes("Content-Type: "+ mime + lineEnd);

outputStream.writeBytes(lineEnd);

byte[]bytes = IOUtils.toByteArray(fileInputStream);
outputStream.write(bytes);

outputStream.writeBytes(lineEnd);
outputStream.writeBytes(twoHyphens + boundary + twoHyphens + lineEnd);

int serverResponseCode = connection.getResponseCode();
String serverResponseMessage = connection.getResponseMessage();
Log.i(HttpUtil.class.getSimpleName(), String.valueOf(serverResponseCode));
Log.i(HttpUtil.class.getSimpleName(), serverResponseMessage);

fileInputStream.close();
outputStream.flush();
outputStream.close();

BufferedReader br=null;
if(connection.getResponseCode()>=200 && connection.getResponseCode()<300)
{
br = new BufferedReader(new InputStreamReader((connection.getInputStream())));

}
else if(connection.getResponseCode()>=400)
{
br = new BufferedReader(new InputStreamReader((connection.getErrorStream())));
}
String inputLine;
while ((inputLine = br.readLine()) != null) {
response.append(inputLine);
}
System.out.println("result from server:"+response.toString());
}
catch (Exception ex)
{
ex.printStackTrace();
}
return response.toString();
}

How to send a multipart request in Android with Volley

As commented, I cannot find where did you process the headers inside MultipartRequest class

So update your class like this:

public class MultipartRequest extends Request<String>{

...
private final Map<String, String> mHeaders;
...

public MultipartRequest(..., Map<String, String> headers, ...) {
super(...);
...
this.mHeaders = headers;
...
}

@Override
public Map<String, String> getHeaders() throws AuthFailureError {
return (mHeaders != null) ? mHeaders : super.getHeaders();
}

...
}


Related Topics



Leave a reply



Submit