If you’re an experienced Android programmer, you’ve probably hand-written a number of onSaveInstanceState and onRestoreInstanceState methods to keep your Activity in state, Since an Activity becomes invisible, the system can reclaim it at any time to free up memory. Overriding the onSaveInstanceState method in an Activity is a Google recommended way to keep the Activity in state.
Best practices recommended by Google
The onSaveInstanceState method will give us a Bundle object to hold the value we want to hold, but the Bundle store is based on the form key-value, so we need to define some additional String key constants. Eventually our project would be filled with code like this:
static final String STATE_SCORE = "playerScore";
static final String STATE_LEVEL = "playerLevel";
// ...
@Override
public void onSaveInstanceState(Bundle savedInstanceState) {
// Save the user's current game state
savedInstanceState.putInt(STATE_SCORE, mCurrentScore);
savedInstanceState.putInt(STATE_LEVEL, mCurrentLevel);
// Always call the superclass so it can save the view hierarchy state
super.onSaveInstanceState(savedInstanceState);
}
Copy the code
After saving the state, in order to restore the state before the system kills the Activity when it is reinstantiated, we retrieve the saved value in the onCreate method:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); // Always call the superclass first
// Check whether we're recreating a previously destroyed instance
if(savedInstanceState ! =null) {
// Restore value of members from saved state
mCurrentScore = savedInstanceState.getInt(STATE_SCORE);
mCurrentLevel = savedInstanceState.getInt(STATE_LEVEL);
} else {
// Probably initialize members with default values for a new instance
}
// ...
}
Copy the code
Of course, this can also be done in the onRestoreInstanceState method:
public void onRestoreInstanceState(Bundle savedInstanceState) {
// Always call the superclass so it can restore the view hierarchy
super.onRestoreInstanceState(savedInstanceState);
// Restore state members from saved instance
mCurrentScore = savedInstanceState.getInt(STATE_SCORE);
mCurrentLevel = savedInstanceState.getInt(STATE_LEVEL);
}
Copy the code
Free your hands
The above scheme is certainly correct. But it’s not elegant. In order to preserve the value of the variable, two methods (onSaveInstanceState and onRestoreInstanceState) and two constants (two constants defined to store the two variables, just to put in the Bundle) are introduced.
To better solve this problem, I wrote the SaveState plugin:
After using the SaveState plugin, this is how to maintain the state of an Activity:
public class MyActivity extends Activity {
@AutoRestore
int myInt;
@AutoRestore
IBinder myRpcCall;
@AutoRestore
String result;
@Override
protected void onCreate(Bundle savedInstanceState) {
// Your code here}}Copy the code
That’s right, you just need to mark the @AutoRestore annotation on the variables you want to hold, and you don’t need to bother with a few Activity callbacks or define redundant String key constants.
So, in addition to activities, can fragments automatically hold state? The answer: Yes!
public class MyFragment extends Fragment {
@AutoRestore
User currentLoginUser;
@AutoRestore
List<Map<String, Object>> networkResponse;
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
// Your code here}}Copy the code
Use the same method as Activity! Not only that, but the usage scenario can also be generalized to views, from which your custom View can also delegate the task of maintaining state to SaveState:
public class MyView extends View {
@AutoRestore
String someText;
@AutoRestore
Size size;
@AutoRestore
float[] myFloatArray;
public MyView(Context context) {
super(context);
}
public MyView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}
public MyView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr); }}Copy the code
Use SaveState now
The way to introduce SaveState is also simple:
First, add the following to the build.gradle file in the project root directory:
buildscript {
repositories {
google()
jcenter()
}
dependencies {
// your other dependencies
// dependency for save-state
classpath "io.github.prototypez:save-state:${latest_version}"}}Copy the code
Then, apply the plugin in the build.gradle file of the Application and Library modules:
apply plugin: 'com.android.application'
// apply plugin: 'com.android.library'
apply plugin: 'save.state'
Copy the code
Everything! No more annoying callbacks to write, because your time is worth a lot! Did a little bit of work, if I save you a cup of coffee time, hope you can help me order a Star, thank you 🙂
SaveState Github: github.com/PrototypeZ/…
Kotlin, Happy Hacking!