Tuesday, April 21, 2015

Restoring activity state after changing configuration

Following are the techniques to save data so that activity can resume from where it had destroyed.

1. onSaveInstanceState()
You can save your serializable data in a bundle and android will save this bundle for you. The same bundle will be returned to you on on in onCreate() and onRestoreInstanceState() callback methods. onRestoreInstanceState() is called after onStart(), whereas onCreate() is called before onStart(). These methods are only called when needed, that is when an activity has been destroyed (because of lack of resources) and needs to be recreated by the system. Because the onCreate() method is called whether the system is creating a new instance of your activity or recreating a previous one, you must check whether the state Bundle is null before you attempt to read it. If it is null, then the system is creating a new instance of the activity, instead of restoring a previous one that was destroyed. e.g.
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    // Check whether we're recreating a previously destroyed instance
    if (savedInstanceState != null) {
        // Restore value of members from saved state
        mUser = savedInstanceState.getString("TEXT");
    } else {
        // Probably initialize members with default values for a new instance
        mUser = "NewUser";
    }
}
@Override
protected void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);
    outState.putString("TEXT", user);
}
2. onRetainNonConfigurationInstance()
The above approach is good for saving serializable things like String, int, custom objects implementing serializable interface, et al. It has can not save objects like Socket. Solution is to override onRetainNonConfigurationInstance. This method was deprecated in API level 13. e.g. declare the following in your activity
 public Object onRetainNonConfigurationInstance() {
   return this;
}

public void onCreate(Bundle savedState)
{
   YourActivity prevActivity = (YourActivity)getLastNonConfigurationInstance();
   if(prevActivity!= null) { 
       // So the orientation did change
       // Restore some field for example
       this.myValue = prevActivity.myValue;
   }
}
3. android:configChanges
Put an android:configChanges entry in our AndroidManifest.xml file, listing the configuration changes we want to handle ourselves without allowing Android to handle for us. Now we can bypass the activity destruction process at any configuration change, and we simply get a callback letting us know of the change. To handle the configuration change implement onConfiguratuionChanged() in activity. However this is a bad practice. Handling configuration changes requires you to take many additional steps to ensure that each and every string, layout, drawable, dimension, etc. remains in sync with the device's current configuration, and if you aren't careful, your application can easily have a whole series of resource-specific bugs as a result.
4. setRetainInstance() for Fragment
Fragments are destroyed and recreated along with their parent Activities when a configuration change occurs. Calling Fragment#setRetainInstance(true) allows us to bypass this destroy-and-recreate cycle, signalling the system to retain the current instance of the fragment when the activity is recreated. This can only be used with fragments not in the back stack.
5. Using onSaveInstanceState in Fragment
In the fragment, save instance state by override onSaveInstanceState and restore on onActivityCreated:
@Override
public void onActivityCreated(Bundle savedInstanceState) {
    super.onActivityCreated(savedInstanceState);
        ...
    if (savedInstanceState != null) {
        //Restore the fragment's state here
    }
}

@Override
public void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);
    //Save the fragment's state here
}
And important point, in the activity, you have to save fragment's instance on onSaveInstanceState and restore on onCreate.
@Override
public void onCreate(Bundle savedInstanceState) {
        ...
    if (savedInstanceState != null) {
        //Restore the fragment's instance
        mContent = getSupportFragmentManager().getFragment(
            savedInstanceState, "mContent");
            ...
    }
        ...
}

@Override
protected void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);

    //Save the fragment's instance
    getSupportFragmentManager().putFragment(outState, "mContent", mContent);
}
Reference
1. http://stackoverflow.com/questions/4096169/onsaveinstancestate-and-onrestoreinstancestate 2. http://stackoverflow.com/questions/16769654/how-to-use-onsaveinstancestate-and-onrestoreinstancestate 3. http://stackoverflow.com/questions/4285877/which-one-to-use-onsaveinstancestate-vs-onretainnonconfigurationinstance 4. http://www.bogotobogo.com/Android/android15Rotation.php 5. http://www.androiddesignpatterns.com/2013/04/retaining-objects-across-config-changes.html 6. http://stackoverflow.com/questions/15313598/once-for-all-how-to-correctly-save-instance-state-of-fragments-in-back-stack

Android aar deployment in Maven - 2022

Introduction If you are working on android library project, you might be wondering how to publish it on Maven like this . Earl...