private void imageBrowse() {
Intent galleryIntent = new Intent(Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
startActivityForResult(galleryIntent, PICK_IMAGE_REQUEST);
}
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == RESULT_OK) {
if(requestCode == PICK_IMAGE_REQUEST){
Uri picUri = data.getData();
FileUpload fileUpload = new FileUpload(getApplicationContext());
filePath = fileUpload.getPath(picUri);
image_preview1.setImageURI(picUri);
}
}
}
can anyone help me to upload multiple images using volley android
Create RestApiMultiPartRequests.class
private class RestApiMultiPartRequests<T> extends Request<T> {
private final Map<String, String> mStringParts;
private final Map<String, File> mFileParts;
private MultipartEntityBuilder mBuilder;
private final Response.Listener<T> mListener;
public RestApiMultiPartRequests(String url,
Map<String, String> stringParts,
Map<String, File> fileParts,
Response.Listener<T> listener,
Response.ErrorListener errorListener) {
super(Method.POST, url, errorListener);
mListener = listener;
mStringParts = stringParts;
mFileParts = fileParts;
buildMultipartEntity();
}
private void buildMultipartEntity() {
if (mBuilder != null) {
mBuilder = null;
}
mBuilder = MultipartEntityBuilder.create();
mBuilder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);
mBuilder.setBoundary("_____" + Long.toString(System.currentTimeMillis()) + "_____");
mBuilder.setCharset(Consts.UTF_8);
if (mStringParts != null) {
for (Map.Entry<String, String> entry : mStringParts.entrySet()) {
mBuilder.addTextBody(entry.getKey(), entry.getValue(), ContentType.create("text/plain", Charset.forName("UTF-8")));
}
}
Log.e("Size", "Size: " + mFileParts.size());
for (Map.Entry<String, File> entry : mFileParts.entrySet()) {
ContentType imageContentType = ContentType.create("image/*");//MULTIPART_FORM_DATA;
Log.d("", "Key " + entry.getKey());
Log.d("", "Value " + entry.getValue());
Log.d("", "Name " + entry.getValue().getName());
//"userfile"
mBuilder.addBinaryBody(entry.getKey(), entry.getValue(), imageContentType, entry.getValue().getName());
}
}
#Override
public String getBodyContentType() {
return mBuilder.build().getContentType().getValue();
}
#Override
public byte[] getBody() {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
try {
mBuilder.build().writeTo(bos);
} catch (IOException e) {
e.printStackTrace();
}
return bos.toByteArray();
}
public HttpEntity getEntity() {
return mBuilder.build();
}
#SuppressWarnings("unchecked")
#Override
protected Response<T> parseNetworkResponse(NetworkResponse response) {
try {
String jsonString = new String(response.data, HttpHeaderParser.parseCharset(response.headers));
return (Response<T>) Response.success(jsonString, HttpHeaderParser.parseCacheHeaders(response));
} catch (UnsupportedEncodingException e) {
return Response.error(new ParseError(e));
}
}
#Override
protected void deliverResponse(T response) {
mListener.onResponse(response);
}
}
and upload image using this method
/**
* Upload image
*/
private void UploadImage() {
RestApiMultiPartRequests<String> restApiMultiPartRequest =
new RestApiMultiPartRequests<String>(url, hashMap, fileparts, new Response.Listener<String>() {
#Override
public void onResponse(String response) {
Log.i(LOG_TAG, "URL " + url + "\n Response : " + response);
if (iRestApiListener != null) {
setparsing(response);
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
// Handle your error types accordingly.For Timeout & No
// connection error, you can show 'retry' button.
// For AuthFailure, you can re login with user
// credentials.
// For ClientError, 400 & 401, Errors happening on
// client side when sending api request.
// In this case you can check how client is forming the
// api and debug accordingly.
// For ServerError 5xx, you can do retry or handle
// accordingly.
int errorCode;
if (error instanceof NetworkError) {
errorCode = NETWORK_ERROR;
Log.i(LOG_TAG, "NetworkError" + error);
} else if (error instanceof ServerError) {
errorCode = SERVER_ERROR;
Log.i(LOG_TAG, "ServerError" + error);
} else if (error instanceof AuthFailureError) {
errorCode = AUTH_FAILURE_ERROR;
Log.i(LOG_TAG, "AuthFailureError" + error);
} else if (error instanceof ParseError) {
errorCode = PARSE_ERROR;
Log.i(LOG_TAG, "ParseError" + error);
} else if (error instanceof NoConnectionError) {
errorCode = NO_CONNECTION_ERROR;
Log.i(LOG_TAG, "NoConnectionError" + error);
} else if (error instanceof TimeoutError) {
errorCode = TIME_OUT_ERROR;
Log.i(LOG_TAG, "TimeoutError" + error);
} else {
errorCode = UNKNOWN_ERROR;
Log.i(LOG_TAG, "TimeoutError" + error);
}
//Log.i(LOG_TAG,"StatusCode" + error.networkResponse.statusCode);
if (iRestApiListener != null) {
iRestApiListener.onCallFinish();
try {
iRestApiListener.onError(new JSONArray());
} catch (JSONException e) {
e.printStackTrace();
}
}
}
}) {
#Override
public Map<String, String> getHeaders() throws AuthFailureError {
Map<String, String> params = new HashMap<String, String>();
if (StringUtils.isNotEmpty(AppClass.preferences.getValueFromPreferance(Preferences.TOKEN))) {
params.put("Authorization", AppClass.preferences.getValueFromPreferance(Preferences.TOKEN));
}
return params;
}
#Override
protected Map<String, String> getParams() throws AuthFailureError {
Map<String, String> params = new HashMap<String, String>();
return params;
}
};
restApiMultiPartRequest.setRetryPolicy(new DefaultRetryPolicy(0, 1, 2));//10000
AppClass.mVolleyInstance.addToRequestQueue(restApiMultiPartRequest);
}
here fileparts is HashMap<String,File> so you can create hash map like this and add multiple file in to it and this single request can upload your multiple image file to server
Related
onActivityResult:
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == REQUEST_CAPTURE_IMAGE && resultCode == RESULT_OK) {
bitmapFrontIC = (Bitmap) data.getExtras().get("data");
frontICImageView.setImageBitmap(bitmapFrontIC);
}else if(requestCode == REQUEST_CAPTURE_BACKIC && resultCode == RESULT_OK){
bitmapBackIC = (Bitmap) data.getExtras().get("data");
backICImageView.setImageBitmap(bitmapBackIC);
}
}
submitbuttonOnClick:
public void submitOnClick(View view){
Log.d("Submit clicked", "Submit Clicked");
if(icNumber.getText().toString().length() > 0 && bitmapFrontIC != null && bitmapBackIC != null){
uploadBitmap(bitmapFrontIC,bitmapBackIC);
}else{
Toast.makeText(getApplicationContext(), "Please fill up all the fields", Toast.LENGTH_SHORT).show();
}
}
GetFileDataFromDrawable:
public byte[] getFileDataFromDrawable(Bitmap bitmap) {
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, byteArrayOutputStream);
return byteArrayOutputStream.toByteArray();
}
uploadBitMap:
private void uploadBitmap(final Bitmap bitmapFrontIC, final Bitmap bitmapBackIC) {
//our custom volley request
VolleyMultipartRequest volleyMultipartRequest = new VolleyMultipartRequest(Request.Method.POST, Constants.API_URL + "/users/upload-ic",
new Response.Listener<NetworkResponse>() {
#Override
public void onResponse(NetworkResponse response) {
loading.dismiss();
try {
JSONObject obj = new JSONObject(new String(response.data));
Toast.makeText(getApplicationContext(), obj.getString("message"), Toast.LENGTH_SHORT).show();
} catch (JSONException e) {
e.printStackTrace();
}
}
},
new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
loading.dismiss();
error.printStackTrace();
NetworkResponse networkResponse = error.networkResponse;
if (networkResponse != null && networkResponse.data != null) {
String errorResponse = new String(networkResponse.data);
try {
JSONObject errorObject = new JSONObject(errorResponse);
if(errorObject.has("error")){
Toast.makeText(ICVerificationActivity.this, errorObject.getString("message"),
Toast.LENGTH_LONG).show();
}
} catch (JSONException e) {
e.printStackTrace();
}
// Print Error!
Log.d("JSON ERROR", errorResponse);
}
}
}) {
/*
* 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("icno", icNumber.getText().toString());
return params;
}
#Override
public Map<String, String> getHeaders() throws AuthFailureError {
HashMap<String, String> headers = new HashMap<String, String>();
headers.put("Content-Type", "multipart/form-data");
headers.put("Authorization", "Bearer " + "abcd");
return headers;
}
/*
* 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("icFront", new DataPart("FrontIC_" + imageName + ".png", getFileDataFromDrawable(bitmapFrontIC)));
params.put("icBack", new DataPart("BackIC_"+imageName + ".png", getFileDataFromDrawable(bitmapBackIC)));
return params;
}
};
//adding the request to volley
Volley.newRequestQueue(this).add(volleyMultipartRequest);
loading.show();
}
I am trying to call the POST request by inputting three items to the body:
a) text
b) camera_image1
c) camera_image2
I am able to display the captured image from camera in the imageview which means the bitmap is working. However, when I want to upload to the server, the server returns that the images are empty. Am I doing it wrongly?
I want to integrate youtube like button in my android app. By refering through this tutorial Videos: rate
I found this api link https://www.googleapis.com/youtube/v3/videos/rate can be used to do that. Can anybody tell me how can I pass a particular video Id along with this api link
Used this code for like youtube Videos....
//getPostLikeBtn (Create this Method.)
private void getPostLikeBtn(final String rating) {
String tag_json_obj = "recipeLike";
final SpotsDialog spotsDialog = new SpotsDialog(context);
spotsDialog.show();
spotsDialog.setMessage("Loading...");
StringRequest jsonObjectRequest = new StringRequest(Request.Method.POST,
"https://www.googleapis.com/youtube/v3/videos/rate",
new Response.Listener<String>() {
#Override
public void onResponse(String response) {
spotsDialog.dismiss();
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
try {
spotsDialog.dismiss();
try {
if (error.networkResponse.data != null) {
try {
String body = new String(error.networkResponse.data, "UTF-8");
Log.e("errorLike", body);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
spotsDialog.dismiss();
Toast.makeText(context, getResources().getString(R.string.try_again), Toast.LENGTH_SHORT).show();
} catch (Exception e) {
e.printStackTrace();
}
Toast.makeText(context, getResources().getString(R.string.try_again), Toast.LENGTH_SHORT).show();
} catch (Exception e) {
e.printStackTrace();
}
// hide the progress dialog
}
}) {
#Override
protected Response<String> parseNetworkResponse(NetworkResponse response) {
int mStatusCode = response.statusCode;
Log.e("mStatusCode", "" + mStatusCode);
if (mStatusCode == 204) {
Toast.makeText(context, "Successfully updated", Toast.LENGTH_SHORT).show();
getLikeShare();
} else {
Toast.makeText(context, getResources().getString(R.string.try_again), Toast.LENGTH_SHORT).show();
}
return super.parseNetworkResponse(response);
}
#Override
public Map<String, String> getHeaders() throws AuthFailureError {
Map<String, String> params = new HashMap<String, String>();
SharedPreferences prefs = getSharedPreferences("GOOGLE_TOKEN", MODE_PRIVATE);
String token = prefs.getString("token", null);
params.put("Authorization", "Bearer " + token);
return params;
}
#Override
protected Map<String, String> getParams() {
Map<String, String> jsonObject = new HashMap<>();
try {
jsonObject.put("id", "Video id");
jsonObject.put("rating", rating);
} catch (Exception e) {
e.printStackTrace();
}
Log.e("jsonObject", "" + jsonObject);
return jsonObject;
}
};
AppController.getInstance().addToRequestQueue(jsonObjectRequest, tag_json_obj);
}
I hope this is usefull for you..
In my android app there is a portion which shows list of pictures. Each picture is associated with a video id.On Clicking that picture corresponding video id will be passed to youtube player and that video will be played in youtube player. Below each picture there is a like button and a comment button. I want to integrate them with youtube like and comment.So that on clicking like or commenting a video in my app is same as clicking like or commenting on youtube. How can I impliment that?
Used this code for like youtube Videos....
//getPostLikeBtn (Create this Method.)
private void getPostLikeBtn(final String rating) {
String tag_json_obj = "recipeLike";
final SpotsDialog spotsDialog = new SpotsDialog(context);
spotsDialog.show();
spotsDialog.setMessage("Loading...");
StringRequest jsonObjectRequest = new StringRequest(Request.Method.POST,
"https://www.googleapis.com/youtube/v3/videos/rate",
new Response.Listener<String>() {
#Override
public void onResponse(String response) {
spotsDialog.dismiss();
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
try {
spotsDialog.dismiss();
try {
if (error.networkResponse.data != null) {
try {
String body = new String(error.networkResponse.data, "UTF-8");
Log.e("errorLike", body);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
spotsDialog.dismiss();
Toast.makeText(context, getResources().getString(R.string.try_again), Toast.LENGTH_SHORT).show();
} catch (Exception e) {
e.printStackTrace();
}
Toast.makeText(context, getResources().getString(R.string.try_again), Toast.LENGTH_SHORT).show();
} catch (Exception e) {
e.printStackTrace();
}
// hide the progress dialog
}
}) {
#Override
protected Response<String> parseNetworkResponse(NetworkResponse response) {
int mStatusCode = response.statusCode;
Log.e("mStatusCode", "" + mStatusCode);
if (mStatusCode == 204) {
Toast.makeText(context, "Successfully updated", Toast.LENGTH_SHORT).show();
getLikeShare();
} else {
Toast.makeText(context, getResources().getString(R.string.try_again), Toast.LENGTH_SHORT).show();
}
return super.parseNetworkResponse(response);
}
#Override
public Map<String, String> getHeaders() throws AuthFailureError {
Map<String, String> params = new HashMap<String, String>();
SharedPreferences prefs = getSharedPreferences("GOOGLE_TOKEN", MODE_PRIVATE);
String token = prefs.getString("token", null);
params.put("Authorization", "Bearer " + token);
return params;
}
#Override
protected Map<String, String> getParams() {
Map<String, String> jsonObject = new HashMap<>();
try {
jsonObject.put("id", "Video id");
jsonObject.put("rating", rating);
} catch (Exception e) {
e.printStackTrace();
}
Log.e("jsonObject", "" + jsonObject);
return jsonObject;
}
};
AppController.getInstance().addToRequestQueue(jsonObjectRequest, tag_json_obj);
}
I hope this is usefull for you..
Hi I am relatively new to android, I have used multipart request to upload an image to server using volley. The image is being uploaded correctly but I am getting the response as null. I checked on postman, I am strangely getting the correct response there.
MultipartRequest.java
public class MultipartRequest extends Request<JSONObject> {
private static final String FILE_PART_NAME = "user[avatar]";
private long cacheTimeToLive = 0;
private MultipartEntityBuilder mBuilder = MultipartEntityBuilder.create();
private final Response.Listener<JSONObject> mListener;
private final File mImageFile;
protected Map<String, String> headers;
public MultipartRequest(String url, File imageFile, Listener<JSONObject> listener, ErrorListener errorListener){
super(Method.PUT, url,errorListener);
mListener = listener;
mImageFile = imageFile;
buildMultipartEntity();
}
#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 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<JSONObject> parseNetworkResponse(NetworkResponse response) {
JSONObject result = null;
return Response.success(result, HttpHeaderParser.parseCacheHeaders(response));
}
#Override
protected void deliverResponse(JSONObject response) {
mListener.onResponse(response);
}
}
uploadImage method :-
private void uploadImage(final Bitmap bitmap){
String name = "DP_"+ userName +".jpeg";
try {
file=bitmapToFile(name,bitmap);
} catch (IOException e) {
e.printStackTrace();
}
MultipartRequest jsonRequest = new MultipartRequest( UPLOAD_URL,
file,
new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
Log.d(TAG,response.toString());
try {
// parseUserPhotoResponse(response);
Picasso.with(getApplicationContext())
.load(destination)
.placeholder(R.mipmap.placeholder)
.resize(avatarSize, avatarSize)
.centerCrop()
.transform(new CircleTransformation())
.into(ivUserProfilePhoto);
} catch (Exception e) {
e.printStackTrace();
}
}
},
new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError volleyError) {
Log.d(TAG, "Error: " + volleyError.getMessage());
if(volleyError!=null)
{
try {
NetworkResponse networkResponse = volleyError.networkResponse;
if (networkResponse != null) {
String responseBody = new String(volleyError.networkResponse.data, "utf-8");
JSONObject jsonObject = new JSONObject(responseBody);
Log.d(TAG, "Response body" + responseBody.toString());
Log.d(TAG, jsonObject.toString());
if (jsonObject.getBoolean("error") == false) {
} else {
Toast.makeText(getApplicationContext(), "" + jsonObject.getString("message"), Toast.LENGTH_LONG).show();
}
}
} catch (JSONException e) {
//Handle a malformed json response
} catch (UnsupportedEncodingException error) {
}
}
}
})
;
//Creating a Request Queue
jsonRequest.setShouldCache(false);
MyApplication.getInstance().addToRequestQueue(jsonRequest, "UPLOAD_IMAGE");
}
I'm using volley library for sending requests and I have a memory leak. I traced it with leak canary and it seems to be from my requests mListeners. after some searching I cancel all my requests in my current activity but still I have a leak I could use some help thanks here is my download code:
(note: I use singleton pattern for getting volley request queue)
private void startImageDownloadService(final NEWS selectedNews) {
if (selectedNews.getIMG_URL() != null && !selectedNews.getIMG_URL().equals("null")) {
ImageRequest imageRequest = new ImageRequest(selectedNews.getIMG_URL(),
new Response.Listener<Bitmap>() {
#Override
public void onResponse(Bitmap bitmap) {
newsImage_imageView.setVisibility(View.VISIBLE);
newsImage_imageView.setImageBitmap(bitmap);
saveImageToFileStarter(bitmap, selectedNews);
}
}, 200, 200, null, null, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError volleyError) {
Toast.makeText(getApplicationContext(), "Failed to download image", Toast.LENGTH_SHORT).show();
}
});
imageRequest.setShouldCache(false);
MyVolleySingleton.getInstance(getApplicationContext()).addToRequestQueue(imageRequest, "newsActivityImage");
//
}
}
private void requestLike(final ImageButton likeButton, final long id) {
try {
StringRequest jsonRequest = new StringRequest(Request.Method.POST, G.likeURL + id + "/like",
new Response.Listener<String>() {
#Override
public void onResponse(String s) {
try {
Log.e("requestLikeJson", s);
JSONObject likeObject = new JSONObject(s);
int likeNumbers = likeObject.getInt("likes");
// Toast.makeText(NewsActivity.this, likeNumbers + "", Toast.LENGTH_LONG)
// .show();
if (likeButton.getTag().equals("notliked")) {
setLikeChangeInDatabase(false, id, likeNumbers);
}
else{
setLikeChangeInDatabase(true, id, likeNumbers);
}
// viewsCount_textView.setText("" + likeNumbers);
} catch (JSONException e) {
e.printStackTrace();
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError volleyError) {
Toast.makeText(NewsActivity.this, "No Internet connection", Toast.LENGTH_LONG).show();
try {
volleyError.printStackTrace();
Log.e("network error", new String(volleyError.networkResponse.data));
} catch (Exception e) {
e.printStackTrace();
}
if (likeButton.getTag().equals("notliked")) {
likeButton.setTag("liked");
likeButtonImageSetter();
} else {
likeButton.setTag("notliked");
likeButtonImageSetter();
}
Animation shake = AnimationUtils.loadAnimation(NewsActivity.this, R.anim.actionfeedback);
likeButton.startAnimation(shake);
}
}) {
#Override
public Priority getPriority() {
return Priority.HIGH;
}
#Override
public Map<String, String> getHeaders() throws AuthFailureError {
Map<String, String> params = new HashMap<>();
Log.e("sent token", "Token " + G.token);
params.put("Authorization", "Token " + G.token);
params.put("Accept-Language", "en-US,en;q=0.8,fa;q=0.6,pt;q=0.4,ar;q=0.2,gl;q=0.2");
return params;
}
#Override
protected Response<String> parseNetworkResponse(NetworkResponse response) {
String utf8String = null;
try {
utf8String = new String(response.data, "UTF-8");
return Response.success(utf8String, HttpHeaderParser.parseCacheHeaders(response));
} catch (UnsupportedEncodingException e) {
return Response.error(new ParseError(e));
}
}
};
jsonRequest.setRetryPolicy(new DefaultRetryPolicy(
G.socketTimeout,
0,
DefaultRetryPolicy.DEFAULT_BACKOFF_MULT));
MyVolleySingleton.getInstance(getApplicationContext()).addToRequestQueue(jsonRequest, "like");
} catch (Exception e) {
}
}
private void requestView(long id) {
try {
StringRequest jsonRequest = new StringRequest(Request.Method.GET, G.viewURL + id + "/view", new Response.Listener<String>() {
#Override
public void onResponse(String s) {
try {
JSONObject viewObject = new JSONObject(s);
Log.e("requestViewJson", s);
} catch (JSONException e) {
e.printStackTrace();
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError volleyError) {
try {
volleyError.printStackTrace();
Log.e("network error", new String(volleyError.networkResponse.data));
} catch (Exception e) {
e.printStackTrace();
}
}
}) {
#Override
public Map<String, String> getHeaders() throws AuthFailureError {
Map<String, String> params = new HashMap<>();
Log.e("sent token", "Token " + G.token);
params.put("Authorization", "Token " + G.token);
params.put("Accept-Language", "en-US,en;q=0.8,fa;q=0.6,pt;q=0.4,ar;q=0.2,gl;q=0.2");
return params;
}
#Override
public Priority getPriority() {
return Priority.HIGH;
}
#Override
protected Response<String> parseNetworkResponse(NetworkResponse response) {
String utf8String = null;
try {
utf8String = new String(response.data, "UTF-8");
return Response.success(utf8String, HttpHeaderParser.parseCacheHeaders(response));
} catch (UnsupportedEncodingException e) {
return Response.error(new ParseError(e));
}
}
};
jsonRequest.setRetryPolicy(new DefaultRetryPolicy(
G.socketTimeout,
0,
DefaultRetryPolicy.DEFAULT_BACKOFF_MULT));
MyVolleySingleton.getInstance(getApplicationContext()).addToRequestQueue(jsonRequest,"view");
} catch (Exception e) {
}
}
and in my onStop() I have :
#Override
protected void onStop() {
try {//new change
MyVolleySingleton.getInstance(getApplicationContext()).cancelPendingRequests("newsActivityImage");
MyVolleySingleton.getInstance(getApplicationContext()).cancelPendingRequests("view");
MyVolleySingleton.getInstance(getApplicationContext()).cancelPendingRequests("like");
loadImageFromFile.cancel(true);
loadImageFromFile=null;
}catch (Exception e){}
super.onStop();
}
After some researching I found that the volley listeners cause the activity leak because they are instantiated as anonymous classes and therefore hold an implicit reference to their outer class (in this example news activity) so I made a separate class for VolleyRequest (just to make them customizable not really related to the leak) and made a listener interface which I implement as an innerclass and use a weak reference to have access to the activity
request code :
public class MyVolleyStringRequest extends com.android.volley.toolbox.StringRequest {
StringResponseListener mListener;
public MyVolleyStringRequest(int method, String url, final StringResponseListener mListener) {
super(method, url, new Response.Listener<String>() {
#Override
public void onResponse(String s) {
mListener.onSuccess(s);
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError volleyError) {
mListener.onFailure(volleyError);
}
});
this.mListener = mListener;
}
#Override
public Map<String, String> getHeaders() throws AuthFailureError {
Map<String, String> params = new HashMap<>();
Log.e("sent token", "Token " + G.token);
params.put("Authorization", "Token " + G.token);
params.put("Accept-Language", "en-US,en;q=0.8,fa;q=0.6,pt;q=0.4,ar;q=0.2,gl;q=0.2");
return params;
}
#Override
protected Response<String> parseNetworkResponse(NetworkResponse response) {
try {
String utf8String = new String(response.data, "UTF-8");
return Response.success(utf8String, HttpHeaderParser.parseCacheHeaders(response));
} catch (UnsupportedEncodingException e) {
return Response.error(new ParseError(e));
}
}
}
requestLike and requestView Code:
private void requestLike(final ImageButton likeButton, final long id) {
MyVolleyStringRequest likeRequest = new MyVolleyStringRequest(Request.Method.POST, G.likeURL + id + "/like",
new RequestLikeStringListener(this));
MyVolleySingleton.getInstance(getApplicationContext()).addToRequestQueue(likeRequest, "like");
}
private void requestView(long id) {
MyVolleyStringRequest viewRequest = new MyVolleyStringRequest(Request.Method.GET, G.viewURL + id + "/view",
new RequestViewStringListener());
MyVolleySingleton.getInstance(getApplicationContext()).addToRequestQueue(viewRequest, "view");
}
listener interface code :
public interface StringResponseListener {
void onSuccess(String response);
void onFailure(VolleyError error);
}
innerclasses code:
public static class RequestLikeStringListener implements StringResponseListener{
WeakReference<NewsActivity> contextWeakReference;
RequestLikeStringListener(NewsActivity context){
contextWeakReference = new WeakReference<>(context);
}
public void onSuccess(String response) {
try {
NewsActivity context = contextWeakReference.get();
if(context != null) {
ImageButton likeButton = (ImageButton) context.findViewById(R.id.likeButton);
Log.e("requestLikeJson", response);
JSONObject likeObject = new JSONObject(response);
int likeNumbers = likeObject.getInt("likes");
if (likeButton.getTag().equals("notliked")) {
context.setLikeChangeInDatabase(false, contextWeakReference.get().id, likeNumbers);
} else {
context.setLikeChangeInDatabase(true, contextWeakReference.get().id, likeNumbers);
}
}
} catch (JSONException e) {
e.printStackTrace();
}
}
public void onFailure(VolleyError error) {
NewsActivity context = contextWeakReference.get();
if(context != null) {
ImageButton likeButton = (ImageButton) context.findViewById(R.id.likeButton);
Toast.makeText(context, "No Internet connection", Toast.LENGTH_LONG).show();
try {
error.printStackTrace();
Log.e("network error", new String(error.networkResponse.data));
} catch (Exception e) {
e.printStackTrace();
}
if (likeButton.getTag().equals("notliked")) {
likeButton.setTag("liked");
context.likeButtonImageSetter();
} else {
likeButton.setTag("notliked");
context.likeButtonImageSetter();
}
Animation shake = AnimationUtils.loadAnimation(context, R.anim.actionfeedback);
likeButton.startAnimation(shake);
}
}
hope it helps someone!