State saving and restoration of custom control (View)

             Relevant programmers of Android development know that if you need to complete some temporary and non-permanent data storage and recovery on the Activity page, one of the methods is to save it through the onSaveInstanceState(Bundle outState) method in the Activity , and then in onRestoreInstanceState(Bundle savedInstanceState) method to restore the previous temporary data, and if the onSaveInstanceState() method is called, the call will occur before the onPause() or onStop() method.

      In fact, even if the developer does not implement the onSaveInstanceState method, some UI space states in the Activity will be saved, mainly because almost all UI controls defined in the Android application framework implement the onSaveInstanceState() method by default, so when the activity is passively destroyed When rebuilding, these UI controls will automatically save and restore state data. For example, EditText editing control, it will automatically save and restore the input data, and CheckBox selection control will also automatically save and restore the selected state. Therefore, as a developer, you only need to Specify a unique Android ID for these controls, and the work of saving and restoring data will be done automatically. If no ID is specified for the control, then the control will not perform automatic data saving and restoring operations.

      Rewrite the usage scenario of the onSaveInstanceState method of the View control. If you need to customize the extended control, inherit the native Android control and add additional member properties, then when saving additional data at this time, you need to override the onSaveInstanceState() method. The specific operation examples are as follows:

The specific scenario is: in the system settings, when setting the ringtone for incoming calls, the system native control RingtonePreference.java class is used to customize and expand to Custom RingtonePreference.java , but it will appear on some low-memory configuration phones, and the Settings process will be killed Dead, causing the ringtone selection preference to be initialized to the default card 1 object, causing the selected ringtone to be saved as the ringtone for card 1 when clicking "OK" to save the ringtone. In this way, if when we set the card 2 ringtone, the low memory is killed, the state is not saved (that is, the card 1 or card 2 we chose?), and it cannot be restored when rebuilding, it will default to the selected one. Card 1 ringtone. The specific code fixes are as follows:

 import android.preference.RingtonePreference;
 import android.provider.Settings;
 import android.util.AttributeSet;
+import android.os.Parcel;
+import android.os.Parcelable;
 import android.provider.MediaStore;
 import java.io.IOException;
 
@@ -199,4 +201,52 @@ public class CustomRingtonePreference extends RingtonePreference {
         mPhoneCount = TelephonyManager.getPhoneCount();
     }
      // 保存数据状态
+    protected Parcelable onSaveInstanceState() {
+        final Parcelable superState = super.onSaveInstanceState();
+        SavedState state = new SavedState(superState);
+        state.phoneId = mPhoneId;
+        return state;
+    }
+      // 恢复数据状态
+    protected void onRestoreInstanceState(Parcelable state) {
+        if (state == null || !state.getClass().equals(SavedState.class)) {
+            // Didn't save state for us in onSaveInstanceState
+            super.onRestoreInstanceState(state);
+            return;
+        }
+
+        SavedState myState = (SavedState) state;
+        super.onRestoreInstanceState(myState.getSuperState());
+        mPhoneId = myState.phoneId;
+    }
+       // 继承 BaseSavedState 类
+    private static class SavedState extends BaseSavedState {
+        int phoneId;
+
+        public SavedState(Parcelable superState) {
+            super(superState);
+        }
+
+        public SavedState(Parcel source) {
+            super(source);
+            phoneId = source.readInt();
+        }
+
+        @Override
+        public void writeToParcel(Parcel dest, int flags) {
+            super.writeToParcel(dest, flags);
+            dest.writeInt(phoneId);
+        }
+
+        public static final Parcelable.Creator<SavedState> CREATOR = new Parcelable.Creator<SavedState>() {
+
+            public SavedState createFromParcel(Parcel in) {
+                return new SavedState(in);
+            }
+
+            public SavedState[] newArray(int size) {
+                return new SavedState[size];
+            }
+        };
+    }
 }
Finally, please pay attention when using: Since the onSaveInstanceState() method may not be called, it is not suitable to save persistent data in this method, such as inserting data into the database. The operation of saving persistent data should be placed in onPause(); the onSaveInstanceState() method is only suitable for saving transient data, such as the state of UI controls, the value of member variables, etc.

Of course, in addition to the system being out of memory and destroying the activity, some system settings changes will also cause the activity to be destroyed and rebuilt. For example, changing the screen orientation, changing the device language setting, and the keyboard pops up.

Guess you like

Origin blog.csdn.net/liu_guizhou/article/details/79141033