I have created a custom Volley Request class which extends Request<NetworkResponse>. Here is the code for that custom class:
public class MultipartRequest extends Request<NetworkResponse> {
private final Response.Listener<NetworkResponse> mListener;
private final Response.ErrorListener mErrorListener;
private final Map<String, String> mHeaders;
private final Map<String, String> mParams;
private final String mMimeType;
private final byte[] mMultipartBody;
public MultipartRequest(String url, Map<String, String> headers, Map<String, String> params, 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.mParams = params;
this.mMimeType = mimeType;
this.mMultipartBody = multipartBody;
}
#Override
public Map<String, String> getHeaders() throws AuthFailureError {
Log.i("MultipartRequest", "headers = " + mHeaders);
return mHeaders;
}
#Override
protected Map<String, String> getParams() throws AuthFailureError {
Log.i("MultipartRequest", "params = " + mParams);
return mParams;
}
#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);
}
}
I have inserted the Log.i statements within getHeaders() and getParams() to ensure they are called properly.I create the request as follows:
final Map<String, String> volleyParams = new HashMap<>();
volleyParams.put("size", String.valueOf(data.imageSize));
volleyParams.put("width", String.valueOf(data.imageWidth));
volleyParams.put("height", String.valueOf(data.imageHeight));
volleyParams.put("isIndex", updateProfilePhoto ? "1" : "0");
final Context context = this;
final String twoHyphens = "--";
final String lineEnd = "\r\n";
final String boundary = "apiclient-" + System.currentTimeMillis();
final String mimeType = "multipart/form-data;boundary=" + boundary;
byte[] multipartBody = new byte[0];
ByteArrayOutputStream bos = new ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream(bos);
try {
// the first file
buildPart(dos, data.thumbnailImageArray, "file0");
// the second file
buildPart(dos, data.scaledImageArray, "file1");
// 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();
}
Map<String, String> headers = new HashMap<String, String>();
headers.put("User-Agent", Authentication.getUserAgent());
headers.put("X-XX-API", Authentication.getKey());
MultipartRequest multipartRequest = new MultipartRequest(BASE_URL + "member/photos", headers, volleyParams, mimeType, multipartBody, new Response.Listener<NetworkResponse>() {
#Override
public void onResponse(NetworkResponse response) {
Log.i(LOG_TAG, "response: " + response);
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Log.i(LOG_TAG, "statusCode = " + error.networkResponse.statusCode);
Log.i(LOG_TAG, "data = " + error.networkResponse.data);
Log.i(LOG_TAG, "headers = " + error.networkResponse.headers);
Log.i(LOG_TAG, "notModified = " + error.networkResponse.notModified);
Log.i(LOG_TAG, "networkTimeMs = " + error.networkResponse.networkTimeMs);
}
});
MySingleton.getInstance(context).addToRequestQueue(multipartRequest);
The call is performed, however the getParams() is never called. How can I ensure the getParams() is always called?
I have had the same problem. You need to override the getBody method and convert all your params to an array of bytes. For example, for a JSON request.
#Override
public String getBodyContentType() {
return "application/json; charset=utf-8";
}
#Override
public byte[] getBody() {
if (mParams == null) {
return null;
}
try {
return new Gson().toJson(mParams).getBytes("utf-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return null;
}
Related
I'm just beginner in Android App development.
I want to upload image files using Android Volley library.
I have used this helper class found somewhere in some blog.:
public class VolleyMultiPartRequest extends Request<NetworkResponse> {
private final String twoHyphens = "--";
private final String lineEnd = "\r\n";
private final String boundary = "apiclient-" + System.currentTimeMillis();
private Response.Listener<NetworkResponse> mListener;
private Response.ErrorListener mErrorListener;
private Map<String, String> mHeaders;
SharedPreferencesManager sharedPreferencesManager =null;
public VolleyMultiPartRequest(int method, String url,
Response.Listener<NetworkResponse> listener,
Response.ErrorListener errorListener, Context context) {
super(method, url, errorListener);
this.mListener = listener;
this.mErrorListener = errorListener;
this.sharedPreferencesManager = new SharedPreferencesManager(context);
}
#Override
public Map<String, String> getHeaders() throws AuthFailureError {
Map<String, String> headers = new HashMap<String, String>();
headers.put("Accept", "application/json");
headers.put("Authorization", "Bearer " + sharedPreferencesManager.retreiveString(AppText.ACCESS_TOKEN));
headers.put("Content-Type", "multipart/form-data");
return headers;
}
#Override
public String getBodyContentType() {
return "multipart/form-data;boundary=" + boundary;
}
#Override
public byte[] getBody() throws AuthFailureError {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream(bos);
try {
// populate text payload
Map<String, String> params = getParams();
if (params != null && params.size() > 0) {
textParse(dos, params, getParamsEncoding());
}
// populate data byte payload
Map<String, DataPart> data = getByteData();
if (data != null && data.size() > 0) {
dataParse(dos, data);
}
// close multipart form data after text and file data
dos.writeBytes(twoHyphens + boundary + twoHyphens + lineEnd);
return bos.toByteArray();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
protected Map<String, DataPart> getByteData() throws AuthFailureError {
return null;
}
#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);
}
private void textParse(DataOutputStream dataOutputStream, Map<String, String> params, String encoding) throws IOException {
try {
for (Map.Entry<String, String> entry : params.entrySet()) {
buildTextPart(dataOutputStream, entry.getKey(), entry.getValue());
}
} catch (UnsupportedEncodingException uee) {
throw new RuntimeException("Encoding not supported: " + encoding, uee);
}
}
private void dataParse(DataOutputStream dataOutputStream, Map<String, DataPart> data) throws IOException {
for (Map.Entry<String, DataPart> entry : data.entrySet()) {
buildDataPart(dataOutputStream, entry.getValue(), entry.getKey());
}
}
private void buildTextPart(DataOutputStream dataOutputStream, String parameterName, String parameterValue) throws IOException {
dataOutputStream.writeBytes(twoHyphens + boundary + lineEnd);
dataOutputStream.writeBytes("Content-Disposition: form-data; name=\"" + parameterName + "\"" + lineEnd);
dataOutputStream.writeBytes(lineEnd);
dataOutputStream.writeBytes(parameterValue + lineEnd);
}
private void buildDataPart(DataOutputStream dataOutputStream, DataPart dataFile, String inputName) throws IOException {
dataOutputStream.writeBytes(twoHyphens + boundary + lineEnd);
dataOutputStream.writeBytes("Content-Disposition: form-data; name=\"" +
inputName + "\"; filename=\"" + dataFile.getFileName() + "\"" + lineEnd);
if (dataFile.getType() != null && !dataFile.getType().trim().isEmpty()) {
dataOutputStream.writeBytes("Content-Type: " + dataFile.getType() + lineEnd);
}
dataOutputStream.writeBytes(lineEnd);
ByteArrayInputStream fileInputStream = new ByteArrayInputStream(dataFile.getContent());
int bytesAvailable = fileInputStream.available();
int maxBufferSize = 1024 * 1024;
int bufferSize = Math.min(bytesAvailable, maxBufferSize);
byte[] buffer = new byte[bufferSize];
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);
}
public class DataPart {
private String fileName;
private byte[] content;
private String type;
public DataPart() {
}
public DataPart(String name, byte[] data) {
fileName = name;
content = data;
}
String getFileName() {
return fileName;
}
byte[] getContent() {
return content;
}
String getType() {
return type;
}
}
}
And called this helper like this:
VolleyMultiPartRequest volleyMultipartRequest = new VolleyMultiPartRequest(Request.Method.POST, Api.UPLOAD_FILE,
new Response.Listener<NetworkResponse>() {
#Override
public void onResponse(NetworkResponse response) {
try {
JSONObject obj = new JSONObject(new String(response.data));
Toast.makeText(context, obj.getString("message"), Toast.LENGTH_SHORT).show();
successCallBack.onSuccess(obj);
} catch (JSONException e) {
e.printStackTrace();
}
}
},
new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Toast.makeText(context, error.getMessage(), Toast.LENGTH_SHORT).show();
try {
errorCallBack.onError(new JSONObject(""));
} catch (JSONException e) {
e.printStackTrace();
}
}
}, context) {
/*
* If you want to add more parameters with the image
* you can do it here
* here we have only one parameter with the image
* which is tags
* */
#Override
protected Map<String, String> getParams() throws AuthFailureError {
Map<String, String> params = new HashMap<>();
params.put("file_for", "post");
params.put("file_type", "image");
return params;
}
/*
* Here we are passing image by renaming it with a unique name
* */
#Override
protected Map<String, DataPart> getByteData() {
Map<String, DataPart> params = new HashMap<>();
long imagename = System.currentTimeMillis();
params.put("images[]", new DataPart(imagename + ".png", getFileDataFromDrawable(bitmap)));
return params;
}
};
I'm getting server error as a response.
I tried different tutorials but didn't find the exact way and easy solution.
In the postman, headers and params are like this, there are an array of images, you can see in photos attached (8 photos). I want to do exact same API call using volley library.
Try this code:
I had similar kind of issue i fixed using this
Uploading multiple files in array using multipart
Add dependecies
compile 'org.apache.httpcomponents:httpcore:4.2.4'
compile 'org.apache.httpcomponents:httpmime:4.2'
compile 'com.mcxiaoke.volley:library:1.0.19'
2.Add in gradle
defaultConfig {
useLibrary 'org.apache.http.legacy'
}
Helper class AndroidMultiPartEntity.java
public class AndroidMultiPartEntity extends MultipartEntity
{
private final ProgressListener listener;
public AndroidMultiPartEntity(final ProgressListener listener) {
super();
this.listener = listener;
}
public AndroidMultiPartEntity(final HttpMultipartMode mode, final ProgressListener listener) {
super(mode);
this.listener = listener;
}
public AndroidMultiPartEntity(HttpMultipartMode mode, final String boundary,
final Charset charset, final ProgressListener listener) {
super(mode, boundary, charset);
this.listener = listener;
}
#Override
public void writeTo(final OutputStream outstream) throws IOException {
super.writeTo(new CountingOutputStream(outstream, this.listener));
}
public interface ProgressListener {
void transferred(long num);
}
public static class CountingOutputStream extends FilterOutputStream {
private final ProgressListener listener;
private long transferred;
public CountingOutputStream(final OutputStream out,
final ProgressListener listener) {
super(out);
this.listener = listener;
this.transferred = 0;
}
public void write(byte[] b, int off, int len) throws IOException {
out.write(b, off, len);
this.transferred += len;
this.listener.transferred(this.transferred);
}
public void write(int b) throws IOException {
out.write(b);
this.transferred++;
this.listener.transferred(this.transferred);
}
}
}
API call method
private class registerCall extends AsyncTask<Void, Integer, String> {
#Override
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected void onProgressUpdate(Integer... progress) {
}
#Override
protected String doInBackground(Void... params) {
return registerMultipartCall();
}
private String registerMultipartCall() {
String responseString = null;
HttpClient httpclient = new DefaultHttpClient();
HttpPost httppost = new HttpPost("URL"); //UPLOAD URL
try {
AndroidMultiPartEntity entity = new AndroidMultiPartEntity(new AndroidMultiPartEntity.ProgressListener() {
#Override
public void transferred(long num) {
}
});
File sourceFile = new File(filePath);
File sourceFile2 = new File(filePath);
entity.addPart("images[0]", new FileBody(sourceFile));
entity.addPart("images[1]", new FileBody(sourceFile2));
//Do your stuff multiple files
entity.addPart("file_type", new StringBody("image");
entity.addPart("file_form", new StringBody("post");
httppost.addHeader("Accept","application/json");
httppost.addHeader("Content-Type", "multipart/form-data");
httppost.addHeader("Authorization", "Bearer " + sharedPreferencesManager.retreiveString(AppText.ACCESS_TOKEN));
httppost.setEntity(entity);
// Making server call
HttpResponse response = httpclient.execute(httppost);
HttpEntity r_entity = response.getEntity();
int statusCode = response.getStatusLine().getStatusCode();
if (statusCode == 200) {
// Server response
statusCode = 200;
responseString = EntityUtils.toString(r_entity);
} else {
statusCode = 200;
responseString = "Error occurred! Http Status Code: " + statusCode;
}
} catch (ClientProtocolException e) {
responseString = e.toString();
} catch (IOException e) {
responseString = e.toString();
}
return responseString;
}
#Override
protected void onPostExecute(String result) {
hideProgressDialog();
}
}
5.Calling Async
new registerCall().execute();
Just replace getByteData() method with this below code:
private dataPartList = ArrayList();
#Override
protected Map<String, List<DataPart>> getByteDataList(){
Map<String, List<DataPart>> params = new HashMap<>();
params.put("yourKey","dataPartList");
return params
}
So, i have this code to make a POST request with volley:
public class MainActivity extends AppCompatActivity {
Button btnSearch;
ProgressDialog loadingDialog;
ListView lvResult;
String session_id;
RequestQueue queue;
MyCookieManager myCookieManager;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btnSearch = (Button) findViewById(R.id.btnSearch);
lvResult = (ListView) findViewById(R.id.lvResult);
loadingDialog = new ProgressDialog(MainActivity.this);
loadingDialog.setMessage("Wait.\nLoading...");
loadingDialog.setCancelable(false);
myCookieManager = new MyCookieManager();
requestCookie(); //FIRST CALL TO GET SESSION ID
btnSearch.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
showLoading();
requestWithSomeHttpHeaders(); //CALL TO MAKE THE REQUEST WITH VALID SESSION ID
}
});
}
public void requestCookie() {
queue = Volley.newRequestQueue(this);
String url = "http://myurl.com/json/";
StringRequest postRequest = new StringRequest(Request.Method.POST, url,
new Response.Listener < String > () {
#Override
public void onResponse(String response) {
//
String x = myCookieManager.getCookieValue();
}
},
new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Log.d("ERROR", "Error => " + error.toString());
hideLoading();
}
}
) {
#Override
public byte[] getBody() throws AuthFailureError {
String httpPostBody = "param1=XPTO¶m2=XPTO";
return httpPostBody.getBytes();
}
#Override
public Map < String, String > getHeaders() throws AuthFailureError {
Map <String, String> params = new HashMap < String, String > ();
params.put("User-Agent", "Mozilla/5.0");
params.put("Accept", "application/json, text/javascript, */*; q=0.01");
params.put("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
//params.put("Set-Cookie", session_id);// + " _ga=GA1.3.1300076726.1496455105; _gid=GA1.3.1624400465.1496455105; _gat=1; _gali=AguardeButton");
//"PHPSESSID=ra0nbm0l22gsnl6s4jo0qkqci1");
return params;
}
protected Response <String> parseNetworkResponse(NetworkResponse response) {
try {
String jsonString = new String(response.data, HttpHeaderParser.parseCharset(response.headers));
String header_response = String.valueOf(response.headers.values());
int index1 = header_response.indexOf("PHPSESSID=");
int index2 = header_response.indexOf("; path");
//Log.e(Utils.tag, "error is : " + index1 + "::" + index2);
session_id = header_response.substring(index1, index2);
return Response.success(jsonString, HttpHeaderParser.parseCacheHeaders(response));
} catch (UnsupportedEncodingException e) {
return Response.error(new ParseError(e));
}
}
};
queue.add(postRequest);
}
public void requestWithSomeHttpHeaders() {
queue = Volley.newRequestQueue(this);
String url = "http://myurl.com/json/";
StringRequest postRequest = new StringRequest(Request.Method.POST, url,
new Response.Listener <String> () {
#Override
public void onResponse(String response) {
Log.d("Response", response);
String x = myCookieManager.getCookieValue();
String status = "";
try {
JSONObject resultObject = new JSONObject(response);
Log.d("JSON RESULT =>", resultObject.toString());
} catch (JSONException e) {
Toast.makeText(MainActivity.this, "Request Error", Toast.LENGTH_SHORT).show();
e.printStackTrace();
}
hideLoading();
}
},
new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Log.d("ERROR", "Error => " + error.toString());
hideLoading();
}
}
) {
#Override
public byte[] getBody() throws AuthFailureError {
String httpPostBody = "param1=XPTO¶m2=XPTO";
return httpPostBody.getBytes();
}
#Override
public Map <String, String> getHeaders() throws AuthFailureError {
Map <String, String> params = new HashMap <String, String> ();
params.put("User-Agent", "Mozilla/5.0");
params.put("Accept", "application/json, text/javascript, */*; q=0.01");
params.put("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
params.put("Cookie", /*myCookieManager.getCookieValue()*/ session_id + "; _ga=GA1.3.1300076726.1496455105; _gid=GA1.3.1624400465.1496455105; _gat=1; _gali=AguardeButton");
return params;
}
};
queue.add(postRequest);
}
private void showLoading() {
runOnUiThread(new Runnable() {
#Override
public void run() {
if (!loadingDialog.isShowing())
loadingDialog.show();
}
});
}
private void hideLoading() {
runOnUiThread(new Runnable() {
#Override
public void run() {
if (loadingDialog.isShowing())
loadingDialog.dismiss();
}
});
}
}
If I send a valid cookie ID this return a valid JSON object else a empty object.
I tried (unsuccessfully) to set default cookie handles like
CookieManager manager = new CookieManager();
CookieHandler.setDefault(manager);
but I get a empty object.
How to put a valid cookie session ID to post request?
So the problem was getting a valid cookie. My mistake was to get it from the POST request itself. I kept the same working principle, getting the cookie when I started the application but using GET instead of POST and calling the root of the URL instead of the address where I get the JSON.
My solution looked like this:
public void requestCookie() {
queue = Volley.newRequestQueue(this);
String url = "http://myurl.com/";
StringRequest getRequest = new StringRequest(Request.Method.GET, url,
new Response.Listener <String> () {
#Override
public void onResponse(String response) {
String x = myCookieManager.getCookieValue();
}
},
new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Log.d("ERROR", "Error => " + error.toString());
hideLoading();
}
}
) {
protected Response <String> parseNetworkResponse(NetworkResponse response) {
try {
String jsonString = new String(response.data, HttpHeaderParser.parseCharset(response.headers));
String header_response = String.valueOf(response.headers.values());
int index1 = header_response.indexOf("PHPSESSID=");
int index2 = header_response.indexOf("; path");
//Log.e(Utils.tag, "error is : " + index1 + "::" + index2);
session_id = header_response.substring(index1, index2);
return Response.success(jsonString, HttpHeaderParser.parseCacheHeaders(response));
} catch (UnsupportedEncodingException e) {
return Response.error(new ParseError(e));
}
}
};
queue.add(getRequest);
}
Using cookies with Android volley library
Request class:
public class StringRequest extends com.android.volley.toolbox.StringRequest {
private final Map<String, String> _params;
/**
* #param method
* #param url
* #param params
* A {#link HashMap} to post with the request. Null is allowed
* and indicates no parameters will be posted along with request.
* #param listener
* #param errorListener
*/
public StringRequest(int method, String url, Map<String, String> params, Listener<String> listener,
ErrorListener errorListener) {
super(method, url, listener, errorListener);
_params = params;
}
#Override
protected Map<String, String> getParams() {
return _params;
}
/* (non-Javadoc)
* #see com.android.volley.toolbox.StringRequest#parseNetworkResponse(com.android.volley.NetworkResponse)
*/
#Override
protected Response<String> parseNetworkResponse(NetworkResponse response) {
// since we don't know which of the two underlying network vehicles
// will Volley use, we have to handle and store session cookies manually
MyApp.get().checkSessionCookie(response.headers);
return super.parseNetworkResponse(response);
}
/* (non-Javadoc)
* #see com.android.volley.Request#getHeaders()
*/
#Override
public Map<String, String> getHeaders() throws AuthFailureError {
Map<String, String> headers = super.getHeaders();
if (headers == null
|| headers.equals(Collections.emptyMap())) {
headers = new HashMap<String, String>();
}
MyApp.get().addSessionCookie(headers);
return headers;
}
}
MyApp:
public class MyApp extends Application {
private static final String SET_COOKIE_KEY = "Set-Cookie";
private static final String COOKIE_KEY = "Cookie";
private static final String SESSION_COOKIE = "sessionid";
private static MyApp _instance;
private RequestQueue _requestQueue;
private SharedPreferences _preferences;
public static MyApp get() {
return _instance;
}
#Override
public void onCreate() {
super.onCreate();
_instance = this;
_preferences = PreferenceManager.getDefaultSharedPreferences(this);
_requestQueue = Volley.newRequestQueue(this);
}
public RequestQueue getRequestQueue() {
return _requestQueue;
}
/**
* Checks the response headers for session cookie and saves it
* if it finds it.
* #param headers Response Headers.
*/
public final void checkSessionCookie(Map<String, String> headers) {
if (headers.containsKey(SET_COOKIE_KEY)
&& headers.get(SET_COOKIE_KEY).startsWith(SESSION_COOKIE)) {
String cookie = headers.get(SET_COOKIE_KEY);
if (cookie.length() > 0) {
String[] splitCookie = cookie.split(";");
String[] splitSessionId = splitCookie[0].split("=");
cookie = splitSessionId[1];
Editor prefEditor = _preferences.edit();
prefEditor.putString(SESSION_COOKIE, cookie);
prefEditor.commit();
}
}
}
/**
* Adds session cookie to headers if exists.
* #param headers
*/
public final void addSessionCookie(Map<String, String> headers) {
String sessionId = _preferences.getString(SESSION_COOKIE, "");
if (sessionId.length() > 0) {
StringBuilder builder = new StringBuilder();
builder.append(SESSION_COOKIE);
builder.append("=");
builder.append(sessionId);
if (headers.containsKey(COOKIE_KEY)) {
builder.append("; ");
builder.append(headers.get(COOKIE_KEY));
}
headers.put(COOKIE_KEY, builder.toString());
}
}
}
You getting cookie (Session id) in Login response, Save cookie in sharedpreference or other db, and use that to send in request.
for getting cookie from login request
CustomStringRequest stringRequest = new CustomStringRequest(Request.Method.POST, SIGN_IN_URL,
new Response.Listener<CustomStringRequest.ResponseM>() {
#Override
public void onResponse(CustomStringRequest.ResponseM result) {
CookieManager cookieManage = new CookieManager();
CookieHandler.setDefault(cookieManage);
progressDialog.hide();
try {
//From here you will get headers
String sessionId = result.headers.get("Set-Cookie");
String responseString = result.response;
Log.e("session", sessionId);
Log.e("responseString", responseString);
JSONObject object = new JSONObject(responseString);
CustomStringRequest class
public class CustomStringRequest extends Request<CustomStringRequest.ResponseM> {
private Response.Listener<CustomStringRequest.ResponseM> mListener;
public CustomStringRequest(int method, String url, Response.Listener<CustomStringRequest.ResponseM> responseListener, Response.ErrorListener listener) {
super(method, url, listener);
this.mListener = responseListener;
}
#Override
protected void deliverResponse(ResponseM response) {
this.mListener.onResponse(response);
}
#Override
protected Response<ResponseM> parseNetworkResponse(NetworkResponse response) {
String parsed;
try {
parsed = new String(response.data, HttpHeaderParser.parseCharset(response.headers));
} catch (UnsupportedEncodingException e) {
parsed = new String(response.data);
}
ResponseM responseM = new ResponseM();
responseM.headers = response.headers;
responseM.response = parsed;
return Response.success(responseM, HttpHeaderParser.parseCacheHeaders(response));
}
public static class ResponseM {
public Map<String, String> headers;
public String response;
}
}
set cookie when add request to server..
#Override
public Map<String, String> getHeaders() throws AuthFailureError {
Map<String, String> headers = new HashMap<String, String>();
String session=sharedPreferences.getString("sessionId","");
headers.put("Cookie",session);
return headers;
}
I am sending multipart Post request in Volley along with the JSon params {as required by server } , but at server side null params are received .
In this request, I need to send Requested params in one part fist, and the image file in the next part .
Map<String, String> params = new HashMap<String, String>();
params.put("appkey", Constants.REQUEST_API_KEY);
params.put("LoginID",issueRequest.getUserName());
params.put("device_id", issueRequest.getImei().toString());
params.put("tokenID", AppSharedPreferance.getAppSharedPreferanceInstance(mContext).getToken(Constants.REQUEST_TOKEN, null));
params.put("issueId", String.valueOf(mRequestIssueId));
params.put("serverID", String.valueOf(mServerId));
JSONObject requestObj = new JSONObject();
requestObj.put("ISSUE_DATA_KEY", new JSONObject(params));
I am requesting like :
PhotoMultipartRequest<JSONObject> photoMultipartRequest=null;
photoMultipartRequest=new PhotoMultipartRequest<JSONObject>(url, requestObj.toString(), new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Log.d(IssueRequest.TAG, "inside Error");
VolleyLog.d(Constants.REQUEST_ERROR, "Error had occured " + error.getCause());
}
}, new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
Log.v(IssueRequest.TAG,"Responce -> Issue Attachments "+response);
String status = null;
int code=-1;
try {
code = (int) response.getInt("error_code");
status = response.getString("response_string");
} catch (JSONException e) {
e.printStackTrace();
}
Log.v(IssueRequest.TAG, "code->" + code + "status->" + status + "Responce ->" + response.toString());
}
},
new File(issue.getAttachmentPath().toString()));
photoMultipartRequest.setRetryPolicy(new RetryPolicyClass());
Log.v(TAG, "Issue data " + photoMultipartRequest.toString());
AppController.getInstance().addToRequestQueue(photoMultipartRequest);
When i am printing the response object, it has null params .
{"response_string":"Invalid request.","error_code":"1","required_params":null}
My VolleyRequest Class :
public class PhotoMultipartRequest<T> extends Request<T> {
private static final String FILE_PART_NAME = "file";
private static final String FILE_JSON_PART_NAME = "parms";
private MultipartEntityBuilder mBuilder = MultipartEntityBuilder.create();
private final Response.Listener<T> mListener;
private final File mImageFile;
protected Map<String, String> headers;
protected String params;
protected static final String PROTOCOL_CHARSET = "utf-8";
public PhotoMultipartRequest(String url, ErrorListener errorListener, Listener<T> listener, File imageFile){
super(Method.POST, url, errorListener);
mListener = listener;
mImageFile = imageFile;
buildMultipartEntity();
}
public PhotoMultipartRequest(String url,String params, ErrorListener errorListener, Listener<T> listener, File imageFile){
super(Method.POST, url, errorListener);
mListener = listener;
mImageFile = imageFile;
this.params=params;
try {
buildMultipartEntity1();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
#Override
public Map<String, String> getHeaders() throws AuthFailureError {
Map<String, String> headers = super.getHeaders();
if (headers == null
|| headers.equals(Collections.emptyMap())) {
headers = new HashMap<String, String>();
}
headers.put("Accept", "application/json");
return headers;
}
private void buildMultipartEntity1() throws UnsupportedEncodingException {
mBuilder.addPart(FILE_JSON_PART_NAME, new StringBody(params));
mBuilder.addBinaryBody(FILE_PART_NAME, mImageFile, ContentType.create("image/jpeg"), mImageFile.getName());
mBuilder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);
mBuilder.setLaxMode().setBoundary("xx").setCharset(Charset.forName("UTF-8"));
}
private void buildMultipartEntity(){
mBuilder.addBinaryBody(FILE_PART_NAME, mImageFile, ContentType.create("image/jpeg"), mImageFile.getName());
mBuilder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);
mBuilder.setLaxMode().setBoundary("xx").setCharset(Charset.forName("UTF-8"));
}
#Override
public String getBodyContentType(){
String contentTypeHeader = mBuilder.build().getContentType().getValue();
return contentTypeHeader;
}
#Override
public byte[] getBody() throws AuthFailureError {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
try {
mBuilder.build().writeTo(bos);
} catch (IOException e) {
VolleyLog.e("IOException writing to ByteArrayOutputStream bos, building the multipart request.");
}
return bos.toByteArray();
}
#Override
protected Response<T> parseNetworkResponse(NetworkResponse response)
{
try {
String result = null;
result = new String( response.data, HttpHeaderParser.parseCharset( response.headers ) );
return ( Response<T> ) Response.success( new JSONObject( result ), HttpHeaderParser.parseCacheHeaders(response) );
} catch ( UnsupportedEncodingException e ) {
return Response.error(new ParseError(e));
} catch (JSONException je) {
return Response.error(new ParseError(je));
}
}
#Override
protected void deliverResponse(T response) {
mListener.onResponse(response);
}
}
I cannot find any clue of what went wrong. So, can anyone help me to correct my request class?
I am trying to upload an image using Volley library in android but no data is being send to the server side as the file is created but it does not contain any data.
public class ProfilePicSendReq extends Request<String>
{
private MultipartEntityBuilder mBuilder = MultipartEntityBuilder.create();
private final Response.Listener<String> mListener;
private final File mImageFile;
protected Map<String, String> headers;
Context context;
public ProfilePicSendReq(Context cntxt, String url, Listener<String> listener, ErrorListener errorListener, File imageFile)
{
super(Method.POST, url, errorListener);
mListener = listener;
mImageFile = imageFile;
buildMultipartEntity();
context = cntxt;
}
#Override
public Map<String, String> getHeaders() throws AuthFailureError
{
headers = super.getHeaders();
if (headers == null
|| headers.equals(Collections.emptyMap()))
{
headers = new HashMap<String, String>();
}
headers.put("Accept", "text/plain");
return headers;
}
private void buildMultipartEntity()
{
mBuilder.addBinaryBody(mImageFile.getName(), mImageFile, ContentType.create("image/jpeg"), "profilePic");
mBuilder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);
mBuilder.setLaxMode().setBoundary("xx").setCharset(Charset.forName("UTF-8"));
}
#Override
public String getBodyContentType()
{
String contentTypeHeader = mBuilder.build().getContentType().getValue();
return contentTypeHeader;
}
#Override
public byte[] getBody() throws AuthFailureError
{
ByteArrayOutputStream bos = new ByteArrayOutputStream();
try {
mBuilder.build().writeTo(bos);
} catch (IOException e) {
Log.d("PicUploadMsg : ", "IOException writing to ByteArrayOutputStream bos, building the multipart request.");
}
return bos.toByteArray();
}
#Override
protected Response<String> parseNetworkResponse(NetworkResponse response)
{
String result = new String(response.data);
return Response.success(result, HttpHeaderParser.parseCacheHeaders(response));
}
#Override
protected void deliverResponse(String response)
{
mListener.onResponse(response);
}
}
It is the famous sending Mulipart data using volley i have tried several time but no data appears to leave from the client side.
I am trying to send multipart data to a server, this data includes also some images.
So i extended Request in this way:
public class MultipartImageRequest extends Request<String> {
private MultipartEntityBuilder entityBuilder = MultipartEntityBuilder.create();
private static final String STRING_PART_NAME = "text";
private final Response.Listener<String> mListener;
private final ArrayList<Bitmap> mFiles = new ArrayList<>();
private HashMap<String, String> mParams = new HashMap<>();
public MultipartImageRequest(String url, Response.ErrorListener errorListener, Response.Listener<String> listener, ArrayList<Bitmap> files, HashMap<String, String> params)
{
super(Method.POST, url, errorListener);
mListener = listener;
mFiles.addAll(files);
mParams = params;
}
private void buildMultipartEntity()
{
int i = 0;
for(Bitmap image : mFiles) {
/*Compress bitmap*/
ByteArrayOutputStream bos = new ByteArrayOutputStream();
image.compress(Bitmap.CompressFormat.JPEG, 50, bos);
entityBuilder.addPart("image_" + i, new ByteArrayBody(bos.toByteArray(), "image_" + i));
i++;
}
StringBuilder paramsBuilder = new StringBuilder();
Iterator<Map.Entry<String, String>> paramIterator = mParams.entrySet().iterator();
while (paramIterator.hasNext()) {
Map.Entry<String,String> entry = paramIterator.next();
entityBuilder.addPart(entry.getKey(), new StringBody(entry.getValue(), ContentType.DEFAULT_TEXT));
}
}
#Override
public String getBodyContentType()
{
return "multipart/form-data; charset=utf-8";
}
#Override
public byte[] getBody() throws AuthFailureError
{
buildMultipartEntity();
ByteArrayOutputStream bos = new ByteArrayOutputStream();
try
{
entityBuilder.build().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
public Map<String, String> getHeaders() throws AuthFailureError {
Map<String,String> params = new HashMap<String, String>();
params.put("Content-Type","multipart/form-data; charset=utf-8");
return params;
}
#Override
protected void deliverResponse(String response)
{
mListener.onResponse(response);
}
}
The problem is that if i set as a content type application/json it works and sends data to the server, but obviously the server gives me back an error 400 because it is expecting a multipart request, rather if i set the content type as multipart/form-data; charset=utf-8 like in the code above Volley just doesn't send the request and gives me an error 500.
I am using RequestBin to check my data and it confirms what i said above.
Also i am using a Rest Client and the request is working with it and on iphone too.
I found the solution on my own, it is important to pass a boundary to the request, otherwise the server will not be able to take our parameters.
It can be done replacing this code:
public MultipartImageRequest(String url, Response.ErrorListener errorListener, Response.Listener<String> listener, ArrayList<Bitmap> files, HashMap<String, String> params)
{
super(Method.POST, url, errorListener);
mListener = listener;
mFiles.addAll(files);
mParams = params;
}
with this one:
public MultipartImageRequest(String url, Response.ErrorListener errorListener, Response.Listener<String> listener, ArrayList<Bitmap> files, HashMap<String, String> params)
{
super(Method.POST, url, errorListener);
mListener = listener;
mFiles.addAll(files);
mParams = params;
entityBuilder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);
entityBuilder.setBoundary(BOUNDARY);
}
and remember to set the boundary string in your Content-Type:
#Override
public String getBodyContentType()
{
return "multipart/form-data; boundary=" + BOUNDARY + "; charset=utf-8";
}
#Override
public Map<String, String> getHeaders() throws AuthFailureError {
Map<String,String> params = new HashMap<String, String>();
params.put("Content-Type","multipart/form-data; boundary=" + BOUNDARY + "; charset=utf-8");
return params;
}