Volley error handling generalized - android

in my application, I've been thinking of the best way to implement 5xx responses from the server.
The first approach was to write my own version of the Request.deliverError method as attached:
#Override
public void deliverError(VolleyError error) {
if(error.networkResponse == null){
super.deliverError(error);
return;
}else {
switch(error.networkResponse.statusCode){
case HttpStatus.SC_HTTP_VERSION_NOT_SUPPORTED:
AppInfo.reportDevInfo(GlideApplication.applicationContext, "got a 505 response for request" +this.toString(), null);
break;
case HttpStatus.SC_INTERNAL_SERVER_ERROR:
case HttpStatus.SC_BAD_GATEWAY:
case HttpStatus.SC_SERVICE_UNAVAILABLE:
case HttpStatus.SC_GATEWAY_TIMEOUT:
int retryCount = RETRY_COUNT - getRetryPolicy().getCurrentRetryCount();
if(retryCount < 0) {
super.deliverError(error);
return;
}
String backoff = error.networkResponse.getHeaders.get("Retry-After");
if(TextUtils.isEmpty(backoof) == false) {
attemptRetryWithNewBackoff(backoff);
return;
}
break;
}
super.deliverError(error)
}
}
}
but that only caused ANRs in the application.
Looking at further research, I found this blog post that showed a way of handling the different response codes, the only issue, is that I'm not sure how to generalise this to my entire application and implementing handling of 5xx response codes with the appropriate "Retry-After" heade.
Having a class that implements ErrorListener and gets a different one as a param in the constructor seems very costly and inefficient:
public class MyErrorListener implements ErrorListener {
ErrorListener mListener;
public MyErrorListener(ErrorListener listener) {
this.mListener = listener;
}
#Override
public void onErrorResponse(VolleyError error) {
if(handleFiveHundredResponse(error) == false) {
this.mListener.onErrorResponse(error);
}
}
}

I know the answer is a bit late, but I'm sure it will definitely help newbies looking for this and This is what I do.
In Kotlin :
Request
val request = object : JsonObjectRequest(Method.POST,
url,
reqObj,
{}, { error ->
Toast.makeText(this, getVolleyError(error), Toast.LENGTH_LONG).show()
}) {
}
RequestController.getInstance().addToRequestQueue(request)
getVolleyError(error: VolleyError)
fun Activity.getVolleyError(error: VolleyError): String {
var errorMsg = ""
if (error is NoConnectionError) {
val cm = getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
var activeNetwork: NetworkInfo? = null
activeNetwork = cm.activeNetworkInfo
errorMsg = if (activeNetwork != null && activeNetwork.isConnectedOrConnecting) {
"Server is not connected to the internet. Please try again"
} else {
"Your device is not connected to internet.please try again with active internet connection"
}
} else if (error is NetworkError || error.cause is ConnectException) {
errorMsg = "Your device is not connected to internet.please try again with active internet connection"
} else if (error.cause is MalformedURLException) {
errorMsg = "That was a bad request please try again…"
} else if (error is ParseError || error.cause is IllegalStateException || error.cause is JSONException || error.cause is XmlPullParserException) {
errorMsg = "There was an error parsing data…"
} else if (error.cause is OutOfMemoryError) {
errorMsg = "Device out of memory"
} else if (error is AuthFailureError) {
errorMsg = "Failed to authenticate user at the server, please contact support"
} else if (error is ServerError || error.cause is ServerError) {
errorMsg = "Internal server error occurred please try again...."
} else if (error is TimeoutError || error.cause is SocketTimeoutException || error.cause is ConnectTimeoutException || error.cause is SocketException || (error.cause!!.message != null && error.cause!!.message!!.contains(
"Your connection has timed out, please try again"
))
) {
errorMsg = "Your connection has timed out, please try again"
} else {
errorMsg = "An unknown error occurred during the operation, please try again"
}
return errorMsg
}
The method I used above is an extension function of kotlin, which can only be called from an activity, if you want to call the same method from another scope, then you have to modify it. an instance of an activity is mandatory to check the internet connectivity
In Java:
Request
JsonObjectRequest request=new JsonObjectRequest(Request.Method.POST,"url",null,new Response.Listener<JSONObject>(){
#Override
public void onResponse(JSONObject response){
}
},new Response.ErrorListener(){
#Override
public void onErrorResponse(VolleyError error){
Toast.makeText(this, getVolleyError(error), Toast.LENGTH_LONG).show()
}
});
RequestController.getInstance().addToRequestQueue(request);
getVolleyError(VolleyError error)
public String getVolleyError(VolleyError error){
String errorMsg="";
if(error instanceof NoConnectionError){
ConnectivityManager cm=(ConnectivityManager)activity.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo activeNetwork=null;
if(cm!=null){
activeNetwork=cm.getActiveNetworkInfo();
}
if(activeNetwork!=null&&activeNetwork.isConnectedOrConnecting()){
errorMsg="Server is not connected to internet.kindly try agian";
}else{
errorMsg="Your device is not connected to internet.please try again with active internet connection";
}
}else if(error instanceof NetworkError||error.getCause()instanceof ConnectException){
errorMsg="Your device is not connected to the internet.";
}else if(error.getCause()instanceof MalformedURLException){
errorMsg="That was a bad request please try again...";
}else if(error instanceof ParseError||error.getCause()instanceof IllegalStateException
||error.getCause()instanceof JSONException
||error.getCause()instanceof XmlPullParserException){
errorMsg="There was an error parsing data...";
}else if(error.getCause()instanceof OutOfMemoryError){
errorMsg="Device out of memory";
}else if(error instanceof AuthFailureError){
errorMsg="Failed to authenticate user at the server, please contact support";
}else if(error instanceof ServerError||error.getCause()instanceof ServerError){
errorMsg="Internal server error occurred please try again....";
}else if(error instanceof TimeoutError||error.getCause()instanceof SocketTimeoutException
||error.getCause()instanceof ConnectTimeoutException
||error.getCause()instanceof SocketException
||(error.getCause().getMessage()!=null
&&error.getCause().getMessage().contains("Connection timed out"))){
errorMsg="Your connection has timed out, please try again";
}else{
errorMsg="Sorry, some thing weird occurred";
}
return errorMsg;
}
The method above should need an instance of an activity to check connectivity, you can provide it as per your logic

I have implemented my own ErrorListener which handle server error responses, here is the code:
public class MyErrorListener implements Response.ErrorListener {
Context context;
View errorView;
TextView errorText;
public MyErrorListener(Context context){
this.context = context;
}
/**
* Handle the preparation to show the errors
*/
public void responsePreparation(){
}
/**
* Handle the client Errors
* #param error
*/
public void clientErrors(int error){
switch(error) {
case 400:
errorText.setText(context.getResources().getString(R.string.error_400_registration));
AlertDialog.Builder error400 = new AlertDialog.Builder(context);
error400.setTitle(context.getResources().getString(R.string.error_400_title_registration));
error400.setView(errorView);
error400.create();
error400.show();
break;
case 401:
errorText.setText(context.getResources().getString(R.string.error_401_registration));
AlertDialog.Builder error401 = new AlertDialog.Builder(context);
error401.setTitle(context.getString(R.string.error_401_title_registration));
error401.setView(errorView);
error401.create();
error401.show();
break;
}
}
#Override
public void onErrorResponse(VolleyError error) {
NetworkResponse response = error.networkResponse;
errorView = View.inflate(context, R.layout.error_dialog, null);
errorText = (TextView) errorView.findViewById(R.id.error_dialog_text);
responsePreparation();
if(response != null && response.data != null){
Log.v("Status code", String.valueOf(error.networkResponse.statusCode));
switch(response.statusCode){
case 400:
case 401:
clientErrors(response.statusCode);
break;
case 500:
errorText.setText(context.getString(R.string.error_502));
AlertDialog.Builder error500 = new AlertDialog.Builder(context);
error500.setTitle(context.getResources().getString(R.string.error_502_title));
error500.setView(errorView);
error500.create();
error500.show();
break;
case 502:
errorText.setText(context.getString(R.string.error_502));
AlertDialog.Builder error502 = new AlertDialog.Builder(context);
error502.setTitle(context.getResources().getString(R.string.error_502_title));
error502.setView(errorView);
error502.create();
error502.show();
break;
}
}
else{
if(checkConnection()){
errorText.setText(context.getResources().getString(R.string.error_502));
AlertDialog.Builder timeoutErrorServer = new AlertDialog.Builder(context);
timeoutErrorServer.setTitle(context.getResources().getString(R.string.error_502_title));
timeoutErrorServer.setView(errorView);
timeoutErrorServer.create();
timeoutErrorServer.show();
}
else{
errorText.setText(context.getResources().getString(R.string.timeout_error));
AlertDialog.Builder timeoutError = new AlertDialog.Builder(context);
timeoutError.setTitle(context.getResources().getString(R.string.timeout_error_title));
timeoutError.setView(errorView);
timeoutError.create();
timeoutError.show();
}
}
}
/**
* Gets the view of the dialog to show
* #return
*/
public View getDialogView(){
return errorView;
}
/**
* Gets the error text to show
* #return
*/
public TextView getErrorText(){
return errorText;
}
/**
* Checks if the user have got connection
* #return Boolean
*/
private Boolean checkConnection(){
ConnectivityManager conMgr = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo i = conMgr.getActiveNetworkInfo();
return !(i == null || !i.isConnected() || !i.isAvailable());
}
}
You can add to the switch the error codes that you want.
Then, when I want to make a new VolleyQuery, I override responsePreparation and clientErrors, like this example:
jsObjRequest = new JsonObjectRequest(Request.Method.POST, url, jsonBody, listener, new MyErrorListener(context){
#Override
public void responsePreparation() {
showProgress(false);
}
#Override
public void clientErrors(int error) {
Log.v("Error message", String.valueOf(error));
switch(error) {
case 400:
getErrorText().setText(context.getResources().getString(R.string.error_400_registration));
AlertDialog.Builder error400 = new AlertDialog.Builder(context);
error400.setTitle(context.getResources().getString(R.string.error_400_title_registration));
error400.setView(getDialogView());
error400.create();
error400.show();
break;
case 401:
getErrorText().setText(context.getResources().getString(R.string.error_401_registration));
AlertDialog.Builder error401 = new AlertDialog.Builder(context);
error401.setTitle(context.getString(R.string.error_401_title_registration));
error401.setView(getDialogView());
error401.create();
error401.show();
break;
}
}
});

new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
if (error instanceof NetworkError) {
} else if (error instanceof ServerError) {
} else if (error instanceof AuthFailureError) {
} else if (error instanceof ParseError) {
} else if (error instanceof NoConnectionError) {
} else if (error instanceof TimeoutError) {
}
}
}

Related

Getting response from server after reconnect the internet volley

While i am hitting URL to get response from server using volley ,during the fetching the net was disconnected .
my question is how to fetch data from server after reconnect the internet connection ,without hitting url once again
private void PostRequest(String Url) {
mRequest = new ServiceRequest(HomeActivity.this);
mRequest.makeServiceRequest(Url, Request.Method.GET, null, new ServiceRequest.ServiceListener() {
#Override
public void onCompleteListener(String response) {
Log.d("reponse", response);
JSONObject object = new JSONObject(response);
}
#Override
public void onErrorListener() {
indicator.setVisibility(View.GONE);
}
});
public void makeServiceRequest(final String url, int method, final
HashMap<String, String> param,ServiceListener listener) {
this.mServiceListener=listener;
stringRequest = new StringRequest(method, url, new Response.Listener<String>
() {
#Override
public void onResponse(String response) {
try {
mServiceListener.onCompleteListener(response);
} catch (Exception e) {
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
try {
if (error instanceof TimeoutError || error instanceof
NoConnectionError) {
} else if (error instanceof AuthFailureError) {
} else if (error instanceof ServerError) {
} else if (error instanceof NetworkError) {
} else if (error instanceof ParseError) {
}
} catch (Exception e) {
}
mServiceListener.onErrorListener();
}
}) {
#Override
protected Map<String, String> getParams() throws AuthFailureError {
return param;
}
#Override
public Map<String, String> getHeaders() throws AuthFailureError {
Map<String, String> headers = new HashMap<String, String>();
return headers;
}
};
//to avoid repeat request Multiple Time
DefaultRetryPolicy retryPolicy = new DefaultRetryPolicy(0, -1,
DefaultRetryPolicy.DEFAULT_BACKOFF_MULT);
stringRequest.setRetryPolicy(retryPolicy);
stringRequest.setRetryPolicy(new DefaultRetryPolicy(30000,
DefaultRetryPolicy.DEFAULT_MAX_RETRIES,
DefaultRetryPolicy.DEFAULT_BACKOFF_MULT));
stringRequest.setShouldCache(false);
AppController.getInstance().addToRequestQueue(stringRequest);
}
}
please give suggetion,before hitting url i was checked internet connection
You can do one thing, create the collection of your failed requests. Register the broadcast receiver of CONNECTIVITY_CHANGE and WIFI_STATE_CHANGED to get notified when the internet connection is available. Once your device connects to the internet, you will get notified in registered broadcast receiver and then send retry all the request which are there in your collection. Once request is successful remove the request from the collection.
You can do with a Network Change Broadcast receiver.
Create a new class NetWorkChangeReceiver
public class NetWorkChangeReceiver extends BroadcastReceiver {
#NonNull
private final NetworkConnectionRestoredListener mListener;
public NetWorkChangeReceiver(#NonNull NetworkConnectionRestoredListener listener) {
mListener = listener;
}
#Override
public void onReceive(Context context, Intent intent) {
if (NetworkUtil.isDeviceConnectedToInternet(context)) {
mListener.onNetworkRestored();
}
}
public interface NetworkConnectionRestoredListener {
void onNetworkRestored();
}
}
Create a NetworkUtil class
#SuppressWarnings("deprecation")
public class NetworkUtil {
private NetworkUtil() {
// no instances
}
public static boolean isDeviceConnectedToInternet(#NonNull Context context) {
ConnectivityManager connManager = (ConnectivityManager) context.getSystemService(
CONNECTIVITY_SERVICE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
for (Network network : connManager.getAllNetworks()) {
if (network != null) {
final NetworkInfo networkInfo = connManager.getNetworkInfo(network);
if (networkInfo != null && networkInfo.isConnected()) {
return true;
}
}
}
return false;
} else {
NetworkInfo mWifi = connManager.getNetworkInfo(TYPE_WIFI);
if (mWifi != null && mWifi.isConnected()) {
return true;
}
NetworkInfo m3G = connManager.getNetworkInfo(TYPE_MOBILE);
if (m3G != null && m3G.isConnected()) {
return true;
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
NetworkInfo mEthernet = connManager.getNetworkInfo(TYPE_ETHERNET);
return mEthernet != null && mEthernet.isConnected();
} else {
return false;
}
}
}
}
In your activity, implement NetWorkChangeReceiver.NetworkConnectionRestoredListener
public class HomeActivity extends AppCompatActivity implements NetWorkChangeReceiver.NetworkConnectionRestoredListener {
NetWorkChangeReceiver mNetworkChangeReceiver;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.home_activity);
//Use this to register the receiver while making the server call.
context.registerReceiver(mNetworkChangeReceiver = new NetWorkChangeReceiver(this), new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION));
}
#Override
public void onNetworkRestored() {
Toast.makeText(this, "Connected", Toast.LENGTH_SHORT).show();
if (mNetworkChangeReceiver != null) {
try {
unregisterReceiver(mNetworkChangeReceiver);
mNetworkChangeReceiver = null;
}
catch (IllegalArgumentException e) {
e.printStackTrace();
}
}
}
#Override
protected void onStop() {
super.onStop();
if (mNetworkChangeReceiver != null) {
try {
unregisterReceiver(mNetworkChangeReceiver);
mNetworkChangeReceiver = null;
}
catch (IllegalArgumentException e) {
e.printStackTrace();
}
}
}
}

Android Volley Request Identity onErrorResponse Section

public void getTestDats(String unique_id) {
final String tag = "testList";
String url = Constants.BASE_URL + "test_module.php";
Map<String, String> params = new HashMap<String, String>();
params.put("user_id", SharedPreferenceUtil.getString(Constants.PrefKeys.PREF_USER_ID, "1"));
params.put("unique_id", unique_id);//1,2,3,4,5
DataRequest loginRequest = new DataRequest(Method.POST, url, params, new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
switch (response.optInt("unique_id")) {
case 1:
//task 1
break;
case 2:
//task 2
break;
default:
//nothing
}
}
}, new ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
//I want to know which unique_id request is failed
}
});
loginRequest.setRetryPolicy(new DefaultRetryPolicy(20000, 0, DefaultRetryPolicy.DEFAULT_BACKOFF_MULT));
AppController.getInstance().addToRequestQueue(loginRequest, tag);
}
I'm trying to identity which request is failed with having unique_id.
I'm calling getTestDats("1") function with unique_id. And function called 10 times and all the api call in addToRequestQueue.
When API go into Success part its working as per code.
But when API go into Error part I didn't identity the request.
Is there any way to know my request param so I can retry with particular unique_id request.
set a field in loginRequest and in onErrorResponse access the field like loginRequest.getUniqueId()
Alternatively, create a seperate class that implements Response.Listener and ErrorListener
Response Listener class:
public class MyReponseListener implements Response.Listener<JSONOBject>{
private long uniqId;
public MyResponseListener(long uniqId){
this.uniqId = uniqId;
}
#Override
public void onResponse(JSONObject response) {
System.out.println("response for uniqId " + uniqId);
// do your other chit chat
}
}
ErrorListener class:
public class MyErrorListener implements ErrorListener{
private long uniqId;
public MyErrorListener(long uniqId){
this.uniqId = uniqId;
}
#Override
public void onErrorResponse(VolleyError error) {
System.out.println("Error for uniqId : " + uniqId);
}
}
Now call it like:
DataRequest loginRequest = new DataRequest(Method.POST, url, params, new MyResponeListener(uniqId), new MyErrorListener(uniqId));
Now if you want some code of the calling class to be accessible in the ErrorListener class then do the following:
1. In calling class put the codes you want to access in methods
2. Create an interface with those method
3. The calling class will implement that interface
4. Pass the interface to constructor of the MyErrorListener or MyResponseListener
for example an activity calls the volley request, on error you want to show a message.
put that show error codes in a method:
public void showMessage(int errorCode){
//message according to code
}
now create an interface
public interface errorMessageInterface{
void showMessage(int errorCode);
}
the activity will implement errorMessageInterface and pass this to the constructor of MyErrorListener and save it in a field.
Inside onErrorResponse, you will call
field.showMessage()
You can parse error response in the same way as you parse success response. I use similar solution in my projects.
public class VolleyErrorParser {
private VolleyError mError;
private String mBody;
private int mUniqueId = -1;
public VolleyErrorParser(VolleyError e){
mError = e;
parseAnswer();
parseBody();
}
private void parseBody() {
if (mBody==null)
return;
try{
JSONObject response = new JSONObject(mBody);
mUniqueId = response.getOptInt("unique_id");
}catch (JSONException e){
e.printStackTrace();
}
}
private void parseAnswer() {
if (mError!=null&&mError.networkResponse!=null&&mError.networkResponse.data!=null){
mBody = new String(mError.networkResponse.data);
}
}
public String getBody(){
return mBody;
}
public int getUniqueId(){
return mUniqueId;
}
}
Use:
...
, new ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
int id = new VolleyErrorParse(error).getUniqueId();
switch (id) {
case -1:
//unique id not found in the answer
break;
case 1:
//task 1
break;
case 2:
//task 2
break;
default:
//nothing
}
}
}
...
Just add this code to identify which type of error you are facing.Add this in your onError() method :
if (error instanceof TimeoutError) {
Log.e(TAG, "TimeoutError");
} else if (error instanceof NoConnectionError) {
Log.e(TAG,"tNoConnectionError");
} else if (error instanceof AuthFailureError) {
Log.e(TAG,"AuthFailureError");
} else if (error instanceof ServerError) {
Log.e(TAG,"ServerError");
} else if (error instanceof NetworkError) {
Log.e(TAG,"NetworkError");
} else if (error instanceof ParseError) {
Log.e(TAG,"ParseError");
}
Log the unique_id before making a request i.e; after params.put("unique_id", unique_id);//1,2,3,4,5. And also once you get the response in onResponse() method. And cross verify what exactly is happening.
most of the solutions here will "work" but they are too complex .. for me :)
here is the simplest option with least code change I can think of:
...
final Map<String, String> params = new HashMap<String, String>();
params.put("user_id", SharedPreferenceUtil.getString(Constants.PrefKeys.PREF_USER_ID, "1"));
params.put("unique_id", unique_id);//1,2,3,4,5
DataRequest loginRequest = new DataRequest(Method.POST, url, params, new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
switch (params.get("unique_id")) {
case 1:
//task 1
break;
case 2:
//task 2
break;
default:
//nothing
}
}
...
All the above answers seem to be correct.But i recommend you to do this in an optimized way. If you will add error handling code in all onErrorResponse() then it will create duplication. So create a seperate method in Utils or some other class and just call that method by passing error object to the method. Also you can inflate some dialog or toast to display an error message.
public static void handleError(final Context context, String alertTitle,
Exception exception, String logTag) {
if (context != null) {
if (exception instanceof TimeoutError)
message = context.getString(R.string.TimeoutError);
else if (exception instanceof NoConnectionError)
message = context.getString(R.string.NoConnectionError);
else if (exception instanceof AuthFailureError)
message = context.getString(R.string.AuthFailureError);
else if (exception instanceof ServerError)
message = context.getString(R.string.ServerError);
else if (exception instanceof NetworkError)
message = context.getString(R.string.NetworkError);
else if (exception instanceof ParseError)
message = context.getString(R.string.ParseError);
message = exception.getMessage();
DialogHelper.showCustomAlertDialog(context, null,
alertTitle, message, "ok",
new OnClickListener() {
#Override
public void onClick(DialogInterface dialog,
int which) {
}
}, null, null);
}
}
I think you have to make one conman method on Base class. As given bellow which I used in my code for calling php web api
/**
* <h1> Use for calling volley webService </h1>
*
* #param cContext Context of activity from where you call the webService
* #param mMethodType Should be POST or GET
* #param mMethodname Name of the method you want to call
* #param URL Url of your webService
* #param mMap Key Values pairs
* #param initialTimeoutMs Timeout of webService in milliseconds
* #param shouldCache Web Api response are stored in catch(true) or not(false)
* #param maxNumRetries maximum number in integer for retries to execute webService
* #param isCancelable set true if you set cancel progressDialog by user event
* #param aActivity pass your activity object
*/
public void callVolley(final Context cContext, String mMethodType, final String mMethodname, String URL,
final HashMap<String, String> mMap, int initialTimeoutMs, boolean shouldCache, int maxNumRetries,
Boolean isProgressDailogEnable, Boolean isCancelable, final Activity aActivity) {
mMap.put("version_key_android",BuildConfig.VERSION_NAME+"");
if (!isOnline(cContext)) {
//showErrorDailog(aActivity, Constant.PleaseCheckInternetConnection, R.drawable.icon);
} else {
StringRequest jsObjRequest;
int reqType = 0;
String RequestURL = URL.trim();
queue = Volley.newRequestQueue(cContext);
if (isProgressDailogEnable) {
customLoaderDialog = new CustomLoaderDialog(cContext);
customLoaderDialog.show(isCancelable);
customLoaderDialog.dialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
#Override
public void onCancel(DialogInterface dialog) {
// finish();
}
});
}
if (mMethodType.trim().equalsIgnoreCase("GET"))
reqType = com.android.volley.Request.Method.GET;
else if (mMethodType.trim().equalsIgnoreCase("POST"))
reqType = com.android.volley.Request.Method.POST;
if (RequestURL.equals(""))
RequestURL = Constant.BASE_URL;
else
RequestURL = URL;
if (Constant.d) Log.d("reqType", reqType + "");
jsObjRequest = new StringRequest(reqType, RequestURL, new com.android.volley.Response.Listener<String>() {
#Override
public void onResponse(String response) {
if (Constant.d) Log.d("response==>" + mMethodname, "" + response);
if (customLoaderDialog != null) {
try {
customLoaderDialog.hide();
} catch (Exception e) {
e.printStackTrace();
}
}
if (response == null || response.length() == 0) {
IVolleyRespose iVolleyRespose = (IVolleyRespose) aActivity;
iVolleyRespose.onVolleyResponse(404, response, mMethodname);
} else {
JSONObject json_str;
try {
json_str = new JSONObject(response);
int status = json_str.getInt("status");
if (status == 100) {
AlertDialog alertDialog = new AlertDialog.Builder(aActivity).create();
alertDialog.setTitle(getResources().getString(R.string.app_name));
alertDialog.setMessage(json_str.getString("message") + "");
alertDialog.setCancelable(false);
alertDialog.setButton(AlertDialog.BUTTON_NEUTRAL, "OK",
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
try {
Intent viewIntent =
new Intent("android.intent.action.VIEW",
Uri.parse(Constant.playStoreUrl));
startActivity(viewIntent);
}catch(Exception e) {
Toast.makeText(getApplicationContext(),"Unable to Connect Try Again...",
Toast.LENGTH_LONG).show();
e.printStackTrace();
}
dialog.dismiss();
// return;
}
});
alertDialog.show();
} else {
IVolleyRespose iVolleyRespose = (IVolleyRespose) aActivity;
iVolleyRespose.onVolleyResponse(RESPONSE_OK, response, mMethodname);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}, new com.android.volley.Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError arg0) {
// TODO Auto-generated method stub
IVolleyRespose iVolleyError = (IVolleyRespose) aActivity;
iVolleyError.onVolleyError(404, "Error", mMethodname);
if (customLoaderDialog != null) {
customLoaderDialog.hide();
}
}
}) {
#Override
protected Map<String, String> getParams() {
String strRequest = "";
try {
strRequest = getWebservicejsObjRequestforvolley(mMethodname, mMap);
if (Constant.d) Log.d("Request==>", strRequest + "");
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Map<String, String> params = new HashMap<>();
params.put("json", strRequest);
return params;
}
#Override
public Map<String, String> getHeaders() throws AuthFailureError {
Map<String, String> params = new HashMap<>();
params.put("Content-Type", "application/x-www-form-urlencoded");
return params;
}
};
//if(Constant.d) Log.d("Request==>", jsObjRequest+"");
jsObjRequest.setTag(mMethodname);
jsObjRequest.setShouldCache(shouldCache);
jsObjRequest.setRetryPolicy(new DefaultRetryPolicy(initialTimeoutMs, maxNumRetries, DefaultRetryPolicy.DEFAULT_BACKOFF_MULT));
queue.add(jsObjRequest);
}
}
Please observe that here we make one interface for getting response and error.
Using Interface you can get method name on both response and error so you can identify which web api is successfully called and which give error. You should extend base class to Activity and also implement Interface which you made for getting volley response. Here in above code I show how to bind interface to activity. when you call api by passing activity context.

Displaying Deezer user playlists in Android app

I'm working on a small Android player I have found on github.
I managed to compile the code, but I'm using the 0.10.16 SDK. it seems the player on github was written for a previous version.
I can log in but when I click on Playlists on the home screen and the code bellow executes, I get a blank screen:
private void getUserPlaylists() {
DeezerRequest request = DeezerRequestFactory.requestCurrentUserPlaylists();
AsyncDeezerTask task = new AsyncDeezerTask(mDeezerConnect,
new JsonRequestListener() {
#SuppressWarnings("unchecked")
#Override
public void onResult(final Object result, final Object requestId) {
mPlaylistList.clear();
try {
mPlaylistList.addAll((List<Playlist>) result);
}
catch (ClassCastException e) {
handleError(e);
}
if (mPlaylistList.isEmpty()) {
Toast.makeText(UserPlaylistsActivity.this, getResources()
.getString(R.string.no_results), Toast.LENGTH_LONG).show();
}
mPlaylistAdapter.notifyDataSetChanged();
}
#Override
public void onComplete(final String response, Object requestId) {
//TODO
Toast.makeText(UserPlaylistsActivity.this, "Playlist_onComplete",
Toast.LENGTH_LONG).show();
}
#Override
public void onUnparsedResult(final String response, Object requestId) {
//TODO
}
#Override
public void onException(Exception exception, Object requestId) {
if(exception instanceof OAuthException){
handleError(exception);
}
else if(exception instanceof MalformedURLException){
handleError(exception);
}
else if(exception instanceof IOException){
handleError(exception);
}
else if(exception instanceof DeezerError){
handleError(exception);
}
else if(exception instanceof JSONException){
handleError(exception);
}
else{
//do nothing
}
}
});
task.execute(request);
}
I think the reason is, that the code above was written for the previous SDK version, which apparently worked with "onResult". The latest SDK however works with "onComplete", which returns an unparsed JSON string.
My questions are:
is there a class built into the SDK that will parse the JSON response
is there a class that will accept the parsed response
is there a function that will display this on screen
I was looking through the documentation, but did not find anything useful.
Did anyone implement this with the latest SDK?
EDIT:
private void getUserPlaylists() {
DeezerRequest request = DeezerRequestFactory.requestCurrentUserPlaylists();
AsyncDeezerTask task = new AsyncDeezerTask(mDeezerConnect,
new JsonRequestListener() {
#SuppressWarnings("unchecked")
#Override
public void onResult(final Object result, final Object requestId) {
mPlaylistList.clear();
try {
mPlaylistList.addAll((List<Playlist>) result);
}
catch (ClassCastException e) {
handleError(e);
}
if (mPlaylistList.isEmpty()) {
Toast.makeText(UserPlaylistsActivity.this, getResources()
.getString(R.string.no_results), Toast.LENGTH_LONG).show();
}
mPlaylistAdapter.notifyDataSetChanged();
}
#Override
public void onUnparsedResult(final String response, Object requestId) {
//TODO
}
#Override
public void onException(Exception exception, Object requestId) {
if(exception instanceof OAuthException){
handleError(exception);
}
else if(exception instanceof MalformedURLException){
handleError(exception);
}
else if(exception instanceof IOException){
handleError(exception);
}
else if(exception instanceof DeezerError){
handleError(exception);
}
else if(exception instanceof JSONException){
handleError(exception);
}
else{
//do nothing
}
}
});
task.execute(request);
}
This works now with 0.10.16 SDK. Removed onComplete() and all data is now beeing parsed correctly. Menus are OK, playback is successful.
The issue is that you're overriding the onComplete(String, Object) method. This method is already present in the JsonRequestListener implementation, so you should not rewrite it yourself, at least not without calling super.onComplete(response, requestId).
When overriding the JsonResultListener class, you should only implement the onResult(Object, Object) as you did, the onUnparsedResult(String, Object) method in case the json can't be parsed automatically, and the onException(Exception, Object) in case an exception occurs.

Android volley last request post call on network drop?

Volley works well when there is network but it goes weird when network drops.
When network is doping ie network strength is going down and i make a post request then nothing happens but once the network regain to full strength it makes the call to the previous post request not the new one?
when i clear the cache it works well...
how to solve this issue, why i am getting previous post response?
// Implements required listeners
public class VolleyServices<T> implements Response.Listener<T>, ErrorListener{
private int id; // request id
private RequestQueue request; // volley request queue
private VolleyResponce<T> listener; // callback listener
private Class<T> clazz; // parsing class
public interface VolleyResponce<T> {
public void OnSuccess(T response,int id);
public void OnError(ServerError error,int id);
}
// Constructor
public VolleyServices(VolleyResponce<T> listener,Context context) {
this.listener = listener;
request = VolleyRequest.getInstance(context).getRequestQueue();
}
// call to post the request with parse class, post parameters in map and request id
public void post(String methodName, HashMap<String, String> map,Class<T> clazz,int id) {
String url = baseUrl + methodName;
this.clazz = clazz;
this.id = id;
GsonRequest<T> myReq = new GsonRequest<T>(Request.Method.POST,url,clazz,map,this,this);
myReq.setTag(id);
request.add(myReq);
}
#Override
public void onResponse(T response) {
if(response != null && clazz == response.getClass()){
listener.OnSuccess(response,this.id);
}
}
#Override
public void onErrorResponse(VolleyError volleyError) {
ServerError error = null;
if(volleyError instanceof NetworkError) {
error = new ServerError("No internet Access, Check your internet connection.","400");
}
if(volleyError instanceof AuthFailureError) {
error = new ServerError("Authentication Failure","400");
}
if(volleyError instanceof ParseError) {
error = new ServerError("Parsing error","400");
}
if(volleyError instanceof NoConnectionError) {
error = new ServerError("No internet Access, Check your internet connection.","400");
}
if(volleyError instanceof TimeoutError) {
error = new ServerError("Request timed out, Please try again later.","400");
}
if(volleyError.networkResponse != null && volleyError.networkResponse.statusCode == 500) {
error = new ServerError("Internal server error","400");
}
else {
try {
if(volleyError.networkResponse != null) {
String responseBody = new String(volleyError.networkResponse.data, "utf-8" );
try{
Gson gson = new Gson();
error = gson.fromJson(responseBody, ServerError.class);
if(error.status == null) {
error.status = "";
}
}catch(Exception e){
e.printStackTrace();
}
} else {
error = new ServerError("Unknown Error","400");
}
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
listener.OnError(error,this.id);
}
Some log message i captured which explains everything in detail
log link

Android: How handle message error from the server using Volley?

I am using Volley for my Android app to fetch data from my server. It works well except when handling the error from my server. My server sends this response when there is a mistake:
{
"status": 400,
"message": "Errors (2): A name is required- Julien is already used. Not creating."
}
My goal is to get the message and then display it in a Toast. I followed some sample for how to do this, but it doesn't work.
There is my error listener :
public void onErrorResponse(VolleyError error) {
int statusCode = error.networkResponse.statusCode;
NetworkResponse response = error.networkResponse;
Log.d("testerror",""+statusCode+" "+response.data);
// 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.
if( error instanceof NetworkError) {
} else if( error instanceof ClientError) {
} else if( error instanceof ServerError) {
} else if( error instanceof AuthFailureError) {
} else if( error instanceof ParseError) {
} else if( error instanceof NoConnectionError) {
} else if( error instanceof TimeoutError) {
}
showProgress(false);
mPasswordView.setError(getString(R.string.error_incorrect_password));
mPasswordView.requestFocus();
}
And there the result of my debugger : testerror﹕ 400 [B#430b8d60
EDIT: Moreover my error.getMessage() is null.
So I don't understand why my variable response.data is not the response from my server.
If someone know how I can get the message from my server it's will be cool.
Thx,
I've implemented something similar to this, and it's relatively simple. Your log message is printing out what looks like gibberish, because response.data is really a byte array - not a String. Also, a VolleyError is really just an extended Exception, so Exception.getMessage() likely wouldn't return what you are looking for unless you override the parsing methods for parsing your VolleyError in your extended Request class. A really basic way to handle this would be to do something like:
//In your extended request class
#Override
protected VolleyError parseNetworkError(VolleyError volleyError){
if(volleyError.networkResponse != null && volleyError.networkResponse.data != null){
VolleyError error = new VolleyError(new String(volleyError.networkResponse.data));
volleyError = error;
}
return volleyError;
}
}
If you add this to your extended Request classes, your getMessage() should at least not return null. I normally don't really bother with this, though, since it's easy enough to do it all from within your onErrorResponse(VolleyError e) method.
You should use a JSON library to simplify things -- I use Gson for example or you could use Apache's JSONObjects which shouldn't require an additional external library. The first step is to get the response JSON sent from your server as a String (in a similar fashion to what I just demonstrated), next you can optionally convert it to a JSONObject (using either apache's JSONObjects and JsonArrays, or another library of your choice) or just parse the String yourself. After that, you just have to display the Toast.
Here's some example code to get you started:
public void onErrorResponse(VolleyError error) {
String json = null;
NetworkResponse response = error.networkResponse;
if(response != null && response.data != null){
switch(response.statusCode){
case 400:
json = new String(response.data);
json = trimMessage(json, "message");
if(json != null) displayMessage(json);
break;
}
//Additional cases
}
}
public String trimMessage(String json, String key){
String trimmedString = null;
try{
JSONObject obj = new JSONObject(json);
trimmedString = obj.getString(key);
} catch(JSONException e){
e.printStackTrace();
return null;
}
return trimmedString;
}
//Somewhere that has access to a context
public void displayMessage(String toastString){
Toast.makeText(context, toastString, Toast.LENGTH_LONG).show();
}
try this class to handle all erros
public class VolleyErrorHelper {
/**
* Returns appropriate message which is to be displayed to the user
* against the specified error object.
*
* #param error
* #param context
* #return
*/
public static String getMessage (Object error , Context context){
if(error instanceof TimeoutError){
return context.getResources().getString(R.string.timeout);
}else if (isServerProblem(error)){
return handleServerError(error ,context);
}else if(isNetworkProblem(error)){
return context.getResources().getString(R.string.nointernet);
}
return context.getResources().getString(R.string.generic_error);
}
private static String handleServerError(Object error, Context context) {
VolleyError er = (VolleyError)error;
NetworkResponse response = er.networkResponse;
if(response != null){
switch (response.statusCode){
case 404:
case 422:
case 401:
try {
// server might return error like this { "error": "Some error occured" }
// Use "Gson" to parse the result
HashMap<String, String> result = new Gson().fromJson(new String(response.data),
new TypeToken<Map<String, String>>() {
}.getType());
if (result != null && result.containsKey("error")) {
return result.get("error");
}
} catch (Exception e) {
e.printStackTrace();
}
// invalid request
return ((VolleyError) error).getMessage();
default:
return context.getResources().getString(R.string.timeout);
}
}
return context.getResources().getString(R.string.generic_error);
}
private static boolean isServerProblem(Object error) {
return (error instanceof ServerError || error instanceof AuthFailureError);
}
private static boolean isNetworkProblem (Object error){
return (error instanceof NetworkError || error instanceof NoConnectionError);
}

Categories

Resources