Activity中使用註解進行狀態儲存
問題描述
一般開發中,當呼叫Activity生命週期方法onPause()和onStop()方法後,Activity的例項並沒有被直接銷燬,它仍然儲存在記憶體中,Activity裡面所有的資訊和狀態資料都將儲存下來,當這個Activity重新回到前臺的時候,所有的資料都會得到保留並且可被使用。
但是在一些特殊情況下,例如裝置上裝載了“XX大師”“XX助手”等清理記憶體的工具時,也有可能直接幹掉我們後臺的Activity,還有一種情況就是當系統的記憶體不足時,垃圾回收機制被自動回收到我們在之前已經onPause()和onStop()的Activity,這樣的話,Activity裡面的資訊和狀態資料都消失了,當重新啟動Activity時,就找不到資料。這時,一般情況我們程式設計師可以在Activity銷燬之前將需要保留下來的資料進行本地化儲存,SharedPrefence是個不錯的選擇的,但是這樣做起來似乎比較麻煩一點。
一般解決辦法
還有一種方法就是使用Activity裡的onSaveInstanceState(Bundle outState)方法裡做一些儲存資料的工作,onSaveInstanceState(Bundle outState)方法傳遞一個Bundle物件,我們使用Bundle物件put一些需要儲存的資料進去,當我們重新將Activity放到前臺工作時,在onCreate()方法中先判斷Bundle是否為空,根據判斷條件來取捨資料來使用,或者直接重寫Activity下的onRestoreInstanceState(Bundle savedInstanceState)方法,在這個方法下取資料。例如:
public class ExampleActivity1 extends Activity { private String mState; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); if (savedInstanceState != null) { mState = savedInstanceState.getString("state"); } } // Activity被回收前,會呼叫這個方法,儲存資料 @Override protected void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); outState.putString("state", mState); } // 也可以在這個方法裡恢復資料 @Override protected void onRestoreInstanceState(Bundle savedInstanceState) { super.onRestoreInstanceState(savedInstanceState); mState = savedInstanceState.getString("state"); } }
以上幾行簡單的程式碼可以解決Activity狀態儲存問題,但是有個問題出現了,如果我們需要儲存的資料不止一兩個一兩種資料型別呢?也可以,我們可以不停的putXXX()不同的資料到Bundle中,然後在不停的getXXX()不同的資料出來使用。可行性是沒有任何問題的,但是稍微顯得有些繁瑣啊,下面就是使用註解來簡化了這樣的一些不必要的重複性的操作,大大簡化了原始碼的書寫。
使用註解儲存狀態資訊
下面是完整的實現程式碼,不難懂,為了便於在Activity裡面使用,要建立一個Activity的基類BaseActivity,在基類中將這些程式碼寫上,以後沒建立一個新的Activity例項都要繼承BaseActivity,保證每個Activity都有相應的狀態資訊儲存方法。
package com.example.activitystatesave;
import java.io.Serializable;
import java.lang.annotation.Annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.Field;
import android.app.Activity;
import android.os.Bundle;
import android.os.Parcelable;
import android.util.Log;
public class BaseActivity extends Activity {
private final String TAG = "BaseActivity";
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface SavedInstanceState {
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 恢復資料
if (savedInstanceState != null) {
restoreInstanceState(savedInstanceState);
}
}
/**
* 儲存狀態
*/
@Override
protected void onSaveInstanceState(Bundle outState) {
Field[] fields = this.getClass().getDeclaredFields();
Field.setAccessible(fields, true);
Annotation[] ans;
for (Field f : fields) {
ans = f.getDeclaredAnnotations();
for (Annotation an : ans) {
if (an instanceof SavedInstanceState) {
try {
Object o = f.get(this);
if (o == null) {
continue;
}
String fieldName = f.getName();
if (o instanceof Integer) {
outState.putInt(fieldName, f.getInt(this));
} else if (o instanceof String) {
outState.putString(fieldName, (String) f.get(this));
} else if (o instanceof Long) {
outState.putLong(fieldName, f.getLong(this));
} else if (o instanceof Short) {
outState.putShort(fieldName, f.getShort(this));
} else if (o instanceof Boolean) {
outState.putBoolean(fieldName, f.getBoolean(this));
} else if (o instanceof Byte) {
outState.putByte(fieldName, f.getByte(this));
} else if (o instanceof Character) {
outState.putChar(fieldName, f.getChar(this));
} else if (o instanceof CharSequence) {
outState.putCharSequence(fieldName, (CharSequence) f.get(this));
} else if (o instanceof Float) {
outState.putFloat(fieldName, f.getFloat(this));
} else if (o instanceof Double) {
outState.putDouble(fieldName, f.getDouble(this));
} else if (o instanceof String[]) {
outState.putStringArray(fieldName, (String[]) f.get(this));
} else if (o instanceof Parcelable) {
outState.putParcelable(fieldName, (Parcelable) f.get(this));
} else if (o instanceof Serializable) {
outState.putSerializable(fieldName, (Serializable) f.get(this));
} else if (o instanceof Bundle) {
outState.putBundle(fieldName, (Bundle) f.get(this));
}
} catch (IllegalArgumentException e) {
Log.e(TAG, e.getMessage());
} catch (IllegalAccessException e) {
Log.e(TAG, e.getMessage());
} catch (Exception e) {
Log.e(TAG, e.getMessage());
}
}
}
}
super.onSaveInstanceState(outState);
}
/**
* 在這裡恢復資料
*
* @param savedInstanceState
*/
private void restoreInstanceState(Bundle savedInstanceState) {
Field[] fields = this.getClass().getDeclaredFields();
Field.setAccessible(fields, true);
Annotation[] ans;
for (Field f : fields) {
ans = f.getDeclaredAnnotations();
for (Annotation an : ans) {
if (an instanceof SavedInstanceState) {
try {
String fieldName = f.getName();
Class cls = f.getType();
if (cls == int.class || cls == Integer.class) {
f.setInt(this, savedInstanceState.getInt(fieldName));
} else if (String.class.isAssignableFrom(cls)) {
f.set(this, savedInstanceState.getString(fieldName));
} else if (Serializable.class.isAssignableFrom(cls)) {
f.set(this, savedInstanceState.getSerializable(fieldName));
} else if (cls == long.class || cls == Long.class) {
f.setLong(this, savedInstanceState.getLong(fieldName));
} else if (cls == short.class || cls == Short.class) {
f.setShort(this, savedInstanceState.getShort(fieldName));
} else if (cls == boolean.class || cls == Boolean.class) {
f.setBoolean(this, savedInstanceState.getBoolean(fieldName));
} else if (cls == byte.class || cls == Byte.class) {
f.setByte(this, savedInstanceState.getByte(fieldName));
} else if (cls == char.class || cls == Character.class) {
f.setChar(this, savedInstanceState.getChar(fieldName));
} else if (CharSequence.class.isAssignableFrom(cls)) {
f.set(this, savedInstanceState.getCharSequence(fieldName));
} else if (cls == float.class || cls == Float.class) {
f.setFloat(this, savedInstanceState.getFloat(fieldName));
} else if (cls == double.class || cls == Double.class) {
f.setDouble(this, savedInstanceState.getDouble(fieldName));
} else if (String[].class.isAssignableFrom(cls)) {
f.set(this, savedInstanceState.getStringArray(fieldName));
} else if (Parcelable.class.isAssignableFrom(cls)) {
f.set(this, savedInstanceState.getParcelable(fieldName));
} else if (Bundle.class.isAssignableFrom(cls)) {
f.set(this, savedInstanceState.getBundle(fieldName));
}
} catch (IllegalArgumentException e) {
Log.e(TAG, e.getMessage());
} catch (IllegalAccessException e) {
Log.e(TAG, e.getMessage());
} catch (Exception e) {
Log.e(TAG, e.getMessage());
}
}
}
}
}
}
以上是全部的BaseActivity的原始碼,使用時建立新的Activity extends BaseActivity,需要哪些成員變數Filed的資料得到儲存,就在哪些成員變數Filed上加上這個定義好的註解。關於註解的基礎知識,可以先找其他的資料看一下,也可以參考,但是這裡講的也特別基礎,希望多瞭解Java註解和反射的,還是去查查其他的資料吧!