Send Images as Multipart with Other Params in Volley Request - java

I was sending a request to the server with two parameters using volley request and it was working fine. Now the requirement has changed and I need to send at least one image or maximum 3 images to the server along with the other two parameters. The image must be sent as multi-part. I have following code for Getting image from gallery and storing their file paths in the list.
List<String> imagePathList = imageFilePaths;
List<MultipartBody.Part> partMap = new ArrayList<>();
for (int i = 0; i < imagePathList.size(); i++) {
Uri fileUri = Uri.parse(imagePathList.get(i));
RequestBody requestFile = RequestBody.create(
MediaType.parse(getMimeTypee(FileUtils.getFile(getContext(), fileUri).getAbsolutePath())),
FileUtils.getFile(getContext(), fileUri)
);
MultipartBody.Part body = MultipartBody.Part.createFormData("court_image[" + i + "]", FileUtils.getFile(getContext(), fileUri).getName(), requestFile);
partMap.add(body);
}
Where imageFilePaths is an ArrayList. The server will receive images like court_image[0], court_image[1] and so on, depends on how many image paths I have in ArrayList.
The volley request is here:
RequestQueue queue = Volley.newRequestQueue(getContext());
StringRequest postRequest = new StringRequest(Request.Method.POST, url1,
new Response.Listener<String>() {
#Override
public void onResponse(String response) {
Toast.makeText(mBaseAppCompatActivity, "Success", Toast.LENGTH_SHORT).show();
}
},
new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
}
}
) {
#Override
public Map<String, String> getHeaders() throws AuthFailureError {
Map<String, String> params = new HashMap<String, String>();
String token = getToken();
params.put("Authorization", "Bearer " + token);
params.put("Content-Type", "multipart/form-data");
return params;
}
#Override
protected Map<String, String> getParams() {
Map<String, String> params = new HashMap<String, String>();
params.put("terms", "true");
params.put("phone", "phoneNo");
return params;
}
};
queue.add(postRequest);
Now the thing is as I am new to the multi-part thing, with the help I am able to get the image from gallery and storing their path in ArrayList but I don't know how to pass the multi-part data in this volley request. Please help.

For uploading the image along with some other parameters, I used volley. However, I found a wrapper of the original volley library which is easier to integrate for multi-part requests. Hence I added the following library in the build.gradle file.
dependencies {
compile 'dev.dworks.libs:volleyplus:+'
}
I removed the original volley library from my build.gradle and used the above library instead which can handle both multi-part and normal requests having similar integration technique.
Then I just had to write the following class which handles the POST request operation.
public class POSTMediasTask {
public void uploadMedia(final Context context, String filePath) {
String url = getUrlForPOSTMedia(); // This is a dummy function which returns the POST url for you
SimpleMultiPartRequest multiPartRequestWithParams = new SimpleMultiPartRequest(Request.Method.POST, url,
new Response.Listener<String>() {
#Override
public void onResponse(String response) {
Log.d("Response", response);
// TODO: Do something on success
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
// TODO: Handle your error here
}
});
// Add the file here
multiPartRequestWithParams.addFile("file", filePath);
// Add the params here
multiPartRequestWithParams.addStringParam("terms", "SomeTerms");
multiPartRequestWithParams.addStringParam("phone", "85050055055");
RequestQueue queue = Volley.newRequestQueue(context);
queue.add(multiPartRequestWithParams);
}
}
Now execute the task like the following.
new POSTMediasTask().uploadMedia(context, mediaPath);
You can upload one file at a time using this library. However, I could manage to upload multiple files, just by initiating multiple tasks.

Related

Android Volley not being recognized as POST on server with php

I am using volley to sent post to my server. in my php inside insert.php i have code like this
if($_SERVER['REQUEST_METHOD'] == 'POST'){
//do all post functions
}
else{
//notofication that says its not post
}
This is my volley code in my android
String HttpUrl = "http://192.168.30.18/insert.php";
// Creating string request with post method
StringRequest stringRequest = new StringRequest(Request.Method.POST, HttpUrl,
new Response.Listener<String>() {
#Override
public void onResponse(String ServerResponse) {
// Hiding the progress dialog after all task complete.
progressDialog.dismiss();
// Showing response message coming from server.
Toast.makeText(CreateAccountOrLoginActivity.this, ServerResponse, Toast.LENGTH_LONG).show();
Log.d("responseSuccess",ServerResponse);
}
},
new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError volleyError) {
// Hiding the progress dialog after all task complete.
progressDialog.dismiss();
// Showing error message if something goes wrong.
Toast.makeText(CreateAccountOrLoginActivity.this, volleyError.toString(), Toast.LENGTH_LONG).show();
Log.d("responseFail",volleyError.toString());
}
}) {
#Override
protected Map<String, String> getParams() {
// Creating Map String Params.
Map<String, String> params = new HashMap<String, String>();
// Adding All values to Params.
params.put("title",title);
params.put("name", fname);
params.put("surname", sname);
return params;
}
};
// Creating RequestQueue.
RequestQueue requestQueue = Volley.newRequestQueue(CreateAccountOrLoginActivity.this);
// Adding the StringRequest object into requestQueue.
requestQueue.add(stringRequest);
The problem is after the android code is run, it returns what is in the else statement of the insert.php instead of what is in the if statement, meaning it is not being recognized as a post. How do i resolve it to make it run in the if statement

Unable to create file on Onedrive through Microsoft Graph Rest API

I am creating an Android app that uploads basic text files to a user's onedrive by using the Microsoft Graph API.
I have discovered by using https://developer.microsoft.com/en-us/graph/graph-explorer to create files using a PUT request with the link "https://graph.microsoft.com/v1.0/me/drive/root:/Test.txt:/children", With the header "Content-Type" "text/plain", and filling the request body with the text to go into the text file. Using the graph explorer, this works without any issues, however when testing my code with all of these things, it always gives me an error 400.
public void saveOpportunityToServer (final String textToSave, String fileName)
{
try
{
StringRequest request = new StringRequest(Request.Method.PUT, "https://graph.microsoft.com/v1.0/me/drive/root:/" + fileName + ":/content",
new Response.Listener<String>() {
#Override
public void onResponse(String response)
{
Log.d ("PAST QUOTES SAVE", "Created file on server");
}
},
new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error)
{
Log.e ("PAST QUOTES SAVE", "Failed to create file on server: " + error.toString());
}
})
{
#Override
public byte[] getBody() throws AuthFailureError {
return textToSave.getBytes();
}
#Override
public Map<String, String> getHeaders() throws AuthFailureError {
HashMap<String, String> headers = new HashMap<String, String>();
headers.put ("Authorization", "Bearer " + mAccessToken);
headers.put ("Content-Type", "text/plain");
return headers;
}
};
serverRequest.getInstance().addToRequestQueue(request, "Create past quote file request");
}catch (Exception e){
Log.e ("PAST QUOTES SAVE", "Failed to create file on server");
}
}
Where serverRequest is an instance of Volley.RequestQueue.
If the function "getBody()" in String Request is left untouched, or the "textToSave" string is empty, the server responds with a success, creates the requested file, but as expected, the file is empty.
Does anyone have a solution, or at least a reason for why the plain text isn't being accepted?
Edit: Request & Response Headers and Body
Headers:
"Authorization" "Bearer [AccessToken]"
"Content-Type" "text/plain"
Body:
"This is a test"
I'm certain the authorization is working, but I guess there is a chance that the server is not properly interpreting the content-type header, however it works on the mentioned website, so I am not sure why it wouldn't in my program.
The response is an empty Error 400, which is stated as a Malformed Request by Microsoft, which leads me to believe the above, however I cant see a way to fix it.
Finally, I found where the issue is.
Due to how volley works, you cannot simply add a "Content-Type" header to the "getHeaders()" function. To change the body content type, you must override a separate function, "geyBodyContentType()"
Here is my final request code, for anyone wondering in the future how to solve this problem.
StringRequest request = new StringRequest(Request.Method.PUT, "https://graph.microsoft.com/v1.0/me/drive/root:/ " + fileName + ":/content",
new Response.Listener<String>() {
#Override
public void onResponse(String response)
{
Log.d ("PAST QUOTES SAVE", "Created file on server");
}
},
new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error)
{
Log.e ("PAST QUOTES SAVE", "Failed to create file on server: " + error.toString());
}
})
{
#Override
public byte[] getBody() throws AuthFailureError {
return textToSave.getBytes();
}
#Override
public Map<String, String> getHeaders() throws AuthFailureError {
HashMap<String, String> headers = new HashMap<String, String>();
headers.put ("Authorization", "Bearer " + mAccessToken);
return headers;
}
#Override
public String getBodyContentType ()
{
return ("text/plain");
}
};

Sending image from Android to Node.js server encodes it in URL style and can't be decoded well

I'm trying to send a photo taken with my phone/emulator camera to a Node.js server, so I'm encoding it to make a string POST request.
I tried to encode it using other answers on the internet, with a byte array stream and a compressed version of the Bitmap. On Node.js I'm trying to decode it with a function that surely works; the problem is the encoding sent to Node.js from Java is bad.
Here is the encoding of the Bitmap:
ByteArrayOutputStream baos = new ByteArrayOutputStream();
imageBitmap.compress(Bitmap.CompressFormat.PNG, 100, baos);
byte[] b = baos.toByteArray();
final String imageEncoded = Base64.encodeToString(b, Base64.DEFAULT);
And my POST request for the string looks like that (I'm using Volley for server interactions):
StringRequest postRequest = new StringRequest(Request.Method.POST, url,
new Response.Listener<String>()
{
#Override
public void onResponse(String response) {
// response
Log.d("RESPONSE", response);
}
},
new Response.ErrorListener()
{
#Override
public void onErrorResponse(VolleyError error) {
// error
Log.d("Error.Response", "ERROR" + error);
}
}
) {
#Override
protected Map<String, String> getParams()
{
Map<String, String> params = new HashMap<String, String>();
params.put("image", imageEncoded);
return params;
}
};
VolleySingleton.getInstance(getApplicationContext()).addToRequestQueue(postRequest);
I'm pretty sure the problem is that my encoding gets some extra % characters when sent to the server, so it can't be decoded well. I thought that in my Node.js code I had to use chunks to make a full string, like this:
http.createServer(function (req, res) {
res.writeHead(200, {'Content-Type': 'text/plain'});
let body = [];
req.on('data', (chunk) => {
body.push(chunk);
}).on('end', () => {
body = Buffer.concat(body).toString();
body = body.split('=');
// More code here
}
My body would look like
"image=iVBORw0KGgoAAAANSUhEUgAAAHgAAACgCAIAAABIaz%2FH..."
so I had to use split to get only the encoding, but still it didn't work. Is there a way to transform this string in another that is not URL encoded like that? Or to get through the POST request without being modified like that?
It looks like you are using the Volley library. If so, you should consider using the JSONObjectRequest instead of the StringRequest. It would look something like this, after you got your image into a JSON String format:
String myImage = "{image:" + imageEncoded + "}"
JSONObject obj = null;
try {
obj = new JSONObject(myImage);
} catch (JSONException e1) {
e1.printStackTrace();
}
JsonObjectRequest postRequest = new JsonObjectRequest(Request.Method.POST,url,obj,
new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
}
},
new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
)} {
#Override
public Map<String, String> getHeaders() throws AuthFailureError {
HashMap<String, String> headers = new HashMap<String, String>();
headers.put("Accept", "application/json; charset=utf-8");
headers.put("Content-Type", "application/json; charset=utf-8");
return headers;
}
};

How do i send Delete request using Volley with Json object as a parameter?

My put method is working fine, but just changing the put request to Delete then its not working,, I tried even by sending its header. but still not working. I even tried Json object to set the parameter. Thanks in advance.
StringRequest stringRequest = new StringRequest(Request.Method.DELETE, url, new Response.Listener<String>() {
#Override
public void onResponse(String response) {
Log.d("blalala", response);
String qtyReserved1 = response.toString();
Toast.makeText(mContext, "ok" + qtyReserved1, Toast.LENGTH_SHORT).show();
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Toast.makeText(mContext, "not ok" + username + Integer.toString(inventoryId), Toast.LENGTH_SHORT).show();
}
})
{
#Override
protected Map<String, String> getParams() throws AuthFailureError {
Map<String, String> params = new HashMap<>();
params.put("screen_name", username);
params.put("inventory_id", Integer.toString(inventoryId));
params.put("pending", "true");
return params;
}
#Override
public String getBodyContentType() {
return "application/json";
}
};
MySingleton.mySingletonInstance(mContext.getApplicationContext()).addToRequestque(stringRequest);
Volley library don't send body when you using DELETE method. You can try other library. I am providing you an example by using loopj library
Add dependency in your gradle
compile 'com.loopj.android:android-async-http:1.4.9'
Request your web Api
RequestParams requestParams = new RequestParams();
requestParams.put("screen_name", "mariyam.shimaanath");
requestParams.put("inventory_id", 19);
requestParams.put("pending", true);
String url="192.168.4.31/api/canteen/cart";
new AsyncHttpClient().delete(url, requestParams, new AsyncHttpResponseHandler() {
#Override
public void onSuccess(int statusCode, Header[] headers, byte[] responseBody) {
String rs = new String(responseBody);
// do whatever you want
}
#Override
public void onFailure(int statusCode, Header[] headers, byte[] responseBody, Throwable error) {
}
});
After lots of research, thank God I'm managed to solve the problem,, Not exactly solved the problem had in Delete request in Volley. But, I had to changed the method i need to request from server side. I changed the request to post method, I know it might not be good practice and solution, but now i managed to delete from sever. thats what i need.

Volley Request Tracking

I am using volley library for uploading images using Restful API
I made multiple image uploading request and add all these into RequestQueue.
when the request is completed I want to perform local db operation based on Request but
now the Question is how can I track the progress of each request
How can I know that which request is finished ?
How can I TAG the request ?
Any Way ?
Code :
StringRequest stringRequest = new StringRequest (Request.Method.POST, Constants.IMAGE_UPLOAD_URL,
new Response.Listener<String> ( ) {
#Override
public void onResponse(String s) {
Log.e (TAG, s.toString ( ));
}
},
new Response.ErrorListener ( ) {
#Override
public void onErrorResponse(VolleyError volleyError) {
}
}) {
#Override
protected Map<String, String> getParams() throws AuthFailureError {
//Creating parameters
Map<String, String> params = new Hashtable<String, String> ( );
//Adding parameters
params.put ("file_contents", imageString);// image string
params.put ("file_name", filenameString);//profile image in name
return params;
}
};
stringRequest.setRetryPolicy (new DefaultRetryPolicy (DefaultRetryPolicy.DEFAULT_TIMEOUT_MS * 2, DefaultRetryPolicy.DEFAULT_MAX_RETRIES, DefaultRetryPolicy.DEFAULT_BACKOFF_MULT));
//Adding request to the queue
if (requestQueue==null)
requestQueue= Volley.newRequestQueue (this);
requestQueue.add (stringRequest);
}
Volley according to the documentation, is not good for long operations and this means that it's not suited for your need
you can extend the request type you're using and add a custom field and then write a RequestFilter that will find the next item according to the returned value of the response
Volley is not suitable for large download or streaming operations,
since Volley holds all responses in memory during parsing. For large
download operations, consider using an alternative like
DownloadManager.

Categories