James James - 1 year ago 88
Android Question

OnSaveInstanceState/ RestCalls

I am relatively new to Android development, and I have a question about onSaveInstanceState(). I am currently working on a login Activity for an app. To check to see if the user can login to their account, I perform a rest call to a server and, based on the response-code, see if I should grant access to the user. The root of my question is based on the fact that I am trying to avoid passing the Activity's Context to my rest-call class. To do this, I create a boolean field in my login Activity representing whether or not the rest-call was successful and a runnable that updates said boolean that I pass to the rest-call class. I know this goes against the idea of an AsyncTask, but I can't find any alternative to simply putting up a dialog box telling the user to wait while this happens. My questions are below.

1) If I use savedInstanceState() in the onCreate method, how do I instantiate this boolean field for the first time? What I mean by this is that after the Activity is destroyed for whatever reason (such as orientation change, etc...) I will use the boolean value stored in my overriden onSaveInstanceState method; however, when it is created for the first time, it has no reference to a boolean value so it has to create one. I currently assign the value before onCreate, but I do not believe this is correct.

2) Does this Runnable even help? I did it so that I wouldn't have to pass the context, but if the Activity is going to be deleted before the RestCall(AsyncTask) is complete, does it really matter whether you pass the context or a Runnable affecting a field of the Activity? The more I think about this, the more I believe it is not going to make much of a difference as it will still result in it pointing to a non-existent object. I am trying to avoid using a Singleton design as I have gathered it is not optimal, but because of the potential lag in time with an AsyncTask, I am beginning to think that it may not be avoidable.

I know onSaveInstanceState() is a topic that has been brought up a lot on StackOverflow, however, I could not find an answer to these questions. I apologize if there has already been a thread for this, but any help or guidance on this would be greatly appreciated! Thank You!

Login Activities' setup:

public class LoginActivity extends Activity implements View.OnClickListener {

private EditText username_et;
private EditText password_et;
private Button login_b;
private boolean login_success = true;
private Runnable run;

* Instances created when app starts

protected void onCreate(Bundle savedInstanceState) {
// login_success = false;
login_success = savedInstanceState.getBoolean("login_success");
username_et = (EditText) findViewById(R.id.username_text);
password_et = (EditText) findViewById(R.id.password_text);
login_b = (Button) findViewById(R.id.login_button);
run = new Runnable() {
public void run() {
login_success = true;

public void onSaveInstanceState(Bundle savedInstanceState){
savedInstanceState.putBoolean("login_success", login_success);

Answer Source

Congratulations. You just discovered Android's dirty little secret.

AsyncTask has an inherent design flaw. It doesn't deal well with configuration changes that happen during background task execution because of exactly the problem you mentioned. It needs to hold a reference to the activity, but there's no guarantee that the reference will still be valid by the time the background task completes.

Here are two ways to overcome this problem:

  1. I refer you to Alex Lockwood's excellent blog post on using hidden fragments with setRetainInstance(true) to span activity destruction and recreation. This is a more involved solution than the next one, but this solution has the advantage that you can still report progress with callbacks. If you were intending to call publishProgress() in your AsyncTask, then this is the method you should use.

  2. Use a Loader. Loaders were designed around database data retrieval in the background, but the fact is that they can also be used to handle remote server access in the background as well. I use a Loader for the majority of my remote server tasks.

    Here's an example:

    public static class ResetPasswordLoader extends AsyncTaskLoader<Pair<CharSequence, Exception>> {
        private static final String TAG = "ResetPasswordLoader ";
        private String mEmail;
        public ResetPasswordLoader(Context context, String email) {
            mEmail = email;
            // set the content-changed flag
        protected void onStartLoading() {
            // only start the load if the content-changed flag is set
            // takeContentChanged() returns the value of the flag before it is cleared
            if (takeContentChanged()) {
        public Pair<CharSequence, Exception> loadInBackground() {
            CharSequence result = null;
            Exception exc = null;
            try {
                result = Service.getInstance().resetPassword(mEmail);
            } catch (RemoteServiceException e) {
                exc = e;
                Log.e(TAG, "loadInBackground(), email = " + mEmail, e);
            return new Pair<>(result, exc);

    Also, in my onLoadFinished() override I make sure to call loaderManager.destroyLoader() on the loader's id.

    Again, Alex Lockwood's blog has some great articles on loaders as well.

For the UI, something I do frequently is put up a indeterminate progress bar over the UI upon calling loaderManager.initLoader(). I also set a boolean like mProgressShown. This boolean gets saved in onSaveInstanceState, so when the activity/fragment is created again, I restore the boolean value which tells me to show the progress bar immediately. Some time later onLoadFinished will be called and I clear mProgressShown and hide the progress bar.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download