自定义控件(View)之状态保存与恢复

             Android开发的相关程序员都知道,如果需要在Activity页面完成对一些临时的、非永久数据存储并进行恢复时,方法之一是通过Activity中的onSaveInstanceState(Bundle outState)方法保存,然后在onRestoreInstanceState(Bundle savedInstanceState)方法中恢复之前的临时数据,并且如果调用onSaveInstanceState()方法的话, 调用将发生在onPause()或onStop()方法之前。

      其实,即使开发者没有实现onSaveInstanceState方法,Activity中的一些UI空间状态也会被保存,主要是由于Android应用框架中定义的几乎所有UI控件都默认实现了onSaveInstanceState()方法, 因此当activity被动的摧毁和重建时, 这些UI控件会自动保存和恢复状态数据. 比如EditText编辑控件,它会自动保存和恢复输入的数据, 而CheckBox选中控件也会自动保存和恢复选中状态. 因此,作为开发者只需要为这些控件指定一个唯一的Android ID, 保存、恢复的数据工作就会自动完成。如果没有为控件指定ID, 那么控件就不会进行自动的数据保存和恢复操作。

      复写View控件的onSaveInstanceState方法的使用场景,如果需要自定义扩展控件时,继承原生Android控件并添加了额外的成员属性,那么此时保存额外的数据时, 就需要覆写onSaveInstanceState()方法。具体操作实例如下:

具体场景为:在系统设置里,进行来电铃声设置时,使用了系统原生控件RingtonePreference.java类进行自定义拓展为 CustomRingtonePreference.java,但是在一些低内存配置手机上会出现,Settings进程会被动杀死,导致铃声选择preference被初始化为默认卡1对象,导致点击“确定”保存铃声时,将选择的铃声保存为卡1的铃声。这样,假如在我们设置的是卡2来电铃声时,出现低内存被杀死,状态没有保存(就是我们选择的卡1还是卡2?),重建时也无法恢复,就会默认到选择的是卡1铃声。具体代码修复如下:

 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];
+            }
+        };
+    }
 }
最后,在使用时请注意:由于onSaveInstanceState()方法方法不一定会被调用, 故不适合在该方法中保存持久化数据, 如向数据库中插入数据等。 保存持久化数据的操作应该放在onPause()中; onSaveInstanceState()方法只适合保存瞬态数据,比如UI控件的状态,成员变量的值等。

当然,除了系统处于内存不足,会摧毁activity之外, 某些系统设置的改变也会导致activity的摧毁和重建. 例如改变屏幕方向,改变设备语言设定,,键盘弹出等。

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值