Android Volley onClick retry not working

I am doing an app which uses volley a lot.

So everywhere in my app when I make a request, Volley tries based on what is set in Retry Policy. If it gets back to me with error, I need to show an AlertDialog with a retry button (and a button for Wifi Settings, preferably)

When retry button is clicked, it should try again which if gets an error again, should show the same AlertDialog again with a retry button.

Meaning, if there's no connection, the AlertDialog should keep coming after timeout period infinitely as long as the user presses retry button.

Volley works fine, but does NOT seem to do anything after the retry button is clicked. i.e., when I call the same jsonObjectRequest addToRequestQueue for the second time.

I can just clearly see that any print logs placed above and below the addToRequestQueue() is getting executed on tapping retry button. But I dont know why I don't get either a response or an error after the second request's been added to queue. Here's what I tried...

SplashActivity.java

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_splash);

    checkConnectionRequest = new JsonObjectRequest(
        Request.Method.POST, 
        getString(R.string.api_root_path) + "/check_connection", 
        JsonProvider.getAnonymousRequestJson(SplashActivity.this), 
        new Response.Listener<JSONObject>() {
            @Override
            public void onResponse(JSONObject response) {
                intent = new Intent(SplashActivity.this, LoginActivity.class);
                startActivity(intent);
                finish();
        }
    }, new Response.ErrorListener() {
        @Override
        public void onErrorResponse(VolleyError error) {
            DialogInterface.OnClickListener onClickTryAgain = new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int which) {
                    makeRequest(checkConnectionRequest);
                }
            };
            if(error instanceof TimeoutError) Alerts.timeoutErrorAlert(SplashActivity.this, onClickTryAgain);
            else if(error instanceof NoConnectionError) Alerts.internetConnectionErrorAlert(SplashActivity.this, onClickTryAgain);
            System.out.println("Response Error: " + error);
        }
    });
    makeRequest(checkConnectionRequest);

}

private void makeRequest(JsonObjectRequest jsonObjectRequest) {
    VolleyClass.getInstance(SplashActivity.this).addToRequestQueue(jsonObjectRequest);
}

Alerts.java

public class Alerts {


    public static void internetConnectionErrorAlert(final Context context, DialogInterface.OnClickListener onClickTryAgainButton) {
        String message = "Sometimes the internet gets a bit sleepy and takes a nap. Make sure its up and running then we'll give it another go";
        new AlertDialog.Builder(context)
                .setCancelable(false)
                .setIconAttribute(android.R.attr.alertDialogIcon)
                .setTitle("Network Error")
                .setMessage(message)
                .setPositiveButton("Try Again", onClickTryAgainButton)
                .setNegativeButton("Turn Internet On", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        Intent i = new Intent(Settings.ACTION_SETTINGS);
                        ((Activity) context).startActivityForResult(i, 0);
                    }
                })
                .show();
    }

    public static void timeoutErrorAlert(Context context, DialogInterface.OnClickListener onClickTryAgainButton) {
        String message = "Are you connected to internet? We guess you aren't. Turn it on and we'll rock and roll!";
        new AlertDialog.Builder(context)
                .setCancelable(false)
                .setIconAttribute(android.R.attr.alertDialogIcon)
                .setTitle("Network Error")
                .setMessage(message)
                .setPositiveButton("Try Again", onClickTryAgainButton)
                .show();
    }

}

PS: I don't want to change the Retry Policy to make it retry as many times as I want. I need to make a request only when the Retry button in popped AlertDialog is pressed.

I initially thought, passing the onclicklisteners to AlertDialog would cause problems, and I tried the same with fragments. No luck though.

What am I doing wrong?


Update:

I intentionally connected to a slow network to test this. I get this after I tap the retry button, is this request NOT send due to something like Busy Socket?

02-04 19:05:27.058 I/System.out: Response Error: com.android.volley.TimeoutError

[ 02-04 19:05:29.078    76:   76 D/         ]
Socket deconnection

[ 02-04 19:05:31.098    76:   76 D/         ]
Socket deconnection

02-04 19:05:31.582 I/System.out: Retrying...
02-04 19:05:31.582 I/System.out: Adding to request queue...!


[ 02-04 19:05:33.122    76:   76 D/         ]
Socket deconnection

[ 02-04 19:05:34.990    76:   76 D/         ]
Socket deconnection

[ 02-04 19:05:36.778    76:   76 D/         ]
Socket deconnection

[ 02-04 19:05:38.726    76:   76 D/         ]
Socket deconnection

Update 2:

I checked if the server is getting any request and replying properly and I just found this

Request is in fact sent to server on addingRequestToQueue for the second time, and the server has replied. However, neither the response nor the error is being captured by volley

At this point, I seriously doubt if this is an error in Volley and perhaps not in my code.

Upvotes: 4

Views: 1816

Answers (2)

Volley DETROYS all listeners as soon as it receives something from the server, regardless of whether the response is a proper response or an error response.

A request needs to constructed everytime it should be sent or resent

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_splash);
    makeRequest();
}

private void makeRequest() {
    JsonObjectRequest checkConnectionRequest = new JsonObjectRequest(
        Request.Method.POST, 
        getString(R.string.api_root_path) + "/check_connection", 
        JsonProvider.getAnonymousRequestJson(SplashActivity.this), 
        new Response.Listener<JSONObject>() {
            @Override
            public void onResponse(JSONObject response) {
                intent = new Intent(SplashActivity.this, LoginActivity.class);
                startActivity(intent);
                finish();
        }
    }, new Response.ErrorListener() {
        @Override
        public void onErrorResponse(VolleyError error) {
            DialogInterface.OnClickListener onClickTryAgain = new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int which) {
                    makeRequest();
                }
            };
            if(error instanceof TimeoutError) Alerts.timeoutErrorAlert(SplashActivity.this, onClickTryAgain);
            else if(error instanceof NoConnectionError) Alerts.internetConnectionErrorAlert(SplashActivity.this, onClickTryAgain);
            System.out.println("Response Error: " + error);
        }
    });
    VolleyClass.getInstance(SplashActivity.this).addToRequestQueue(jsonObjectRequest);
}

Upvotes: 0

kalin
kalin

Reputation: 3576

you should never put the same request object instance again in the queue. Request has a state and apart from other inconsistency the callbacks will not be called again when the same request instance delivers and answer. Check my answer here.

the solution is to clone the request.

Upvotes: 2

Related Questions