Search code examples
javaandroidrobospice

How to recover properly recover from an interupted uncached request using RoboSpice


I have a simple fragment that handles logins for my application. Since I'm dealing with login requests, I do not want to cache them. This strategy works fine until I introduce a suspend or orientation change in the middle of the request. When a user clicks the login button I display a ProgressDialog. This goes away when I get the response (success or fail). If I go to the home screen and then go back into the app during the middle of a login request, my Listener never gets notified and as a result my ProgressDialog doesn't get dismissed and my application is frozen. I tried adding spiceManager.getFromCache in my onStart. This helps, but the result is always null when the app tries to recover... this makes sense since the results aren't cached. What is the proper way to configure my listener to be notified in this scenario?

// using Jackson2SpringAndroidSpiceService

public void onStart() {
    super.onStart();
    spiceManager.start(getActivity());
    spiceManager.addListenerIfPending(AccessTokenResponse.class, null,
            new AccessTokenResponseRequestListener());

    //spiceManager.getFromCache(AccessTokenResponse.class,
    //        null, DurationInMillis.ALWAYS_EXPIRED,
    //        new AccessTokenResponseRequestListener());
}


private void performRequest(String username, String password) {
    progressDialog = ProgressDialog.show(getActivity(), "", "Logging in...", true);
    LoginFragment.this.getActivity().setProgressBarIndeterminateVisibility(true);
    LoginRequest request = new LoginRequest(username, password);
    spiceManager.execute(request, null, DurationInMillis.ALWAYS_EXPIRED, new AccessTokenResponseRequestListener());
}


private class AccessTokenResponseRequestListener implements RequestListener<AccessTokenResponse> {

    @Override
    public void onRequestFailure(SpiceException e) {
        //update your UI
        if(progressDialog != null && progressDialog.isShowing()) {
            progressDialog.dismiss();
        }
        buttonLogin.setEnabled(true);
        Log.e(TAG, "Login unsuccessful");
        if(e.getCause() instanceof HttpClientErrorException)
        {
            HttpClientErrorException exception = (HttpClientErrorException)e.getCause();
            if(exception.getStatusCode().equals(HttpStatus.BAD_REQUEST))
            {
                Log.e(TAG, "Login unsuccessful");
                Toast.makeText(getActivity().getApplicationContext(),
                        "Wrong username/password combo!",
                        Toast.LENGTH_LONG).show();
            }
            else
            {
                Toast.makeText(getActivity().getApplicationContext(),
                        "Login unsuccessful! If the problem persists, please contact support.",
                        Toast.LENGTH_LONG).show();
            }
        } else {
            Toast.makeText(getActivity().getApplicationContext(),
                "Login unsuccessful! If the problem persists, please contact support.",
                Toast.LENGTH_LONG).show();
        }
    }

    @Override
    public void onRequestSuccess(AccessTokenResponse accessToken) {
        //update  UI
        if(progressDialog != null && progressDialog.isShowing()) {
            progressDialog.dismiss();
        }
        buttonLogin.setEnabled(true);

        if (accessToken != null) { 
            OnAuthenticatedListener listener = (OnAuthenticatedListener) getActivity();
            listener.userLoggedIn(editTextUsername.getText().toString(), accessToken);
        }

    }
}

Solution

  • Use cache. Execute request with some cache key

    spiceManager.execute(request, "your_cache_key", DurationInMillis.ALWAYS_EXPIRED, new AccessTokenResponseRequestListener());
    

    and in listener remove response on this request from cache if it returned successfully before you switched to another activity as you do not want to cache the account information as per your requirement.

    @Override
    public void onRequestFailure(SpiceException e) {
        ....
        spiceManager.removeDataFromCache(AccessTokenResponse.class);
        ....
    }
    
    @Override
    public void onRequestSuccess(AccessTokenResponse accessToken) {
        if (accessToken == null) {
            return;
        }
        ....
        spiceManager.removeDataFromCache(AccessTokenResponse.class);
        ....
    }
    

    In onStart try to get cached response if you switched to another activity and now come back to the previous activity. This return response which arrive after you call spiceManager.shouldStop(). Otherwise return null.

    spiceManager.getFromCache(AccessTokenResponse.class, "your_cache_key", DurationInMillis.ALWAYS_RETURNED, new AccessTokenResponseRequestListener());