states中文 - android studio activity




使用“保存實例狀態”保存Android活動狀態 (18)

將LiveData(Android架構組件)添加到項目中

添加以下依賴項

implementation "android.arch.lifecycle:extensions:1.1.0"

LiveData接收觀察者並僅在數據更改處於STARTED或RESUMED狀態時通知它。與LiveData的好處是,當你的活動進入其他比任何國家已啟動會不會調用調用onChanged的方法觀測

private TextView mTextView;
private MutableLiveData<String> mMutableLiveData;

@Override
protected void onCreate(Bundle savedInstanceState) {
    mTextView = (TextView) findViewById(R.id.textView);
    mMutableLiveData = new MutableLiveData<>();
    mMutableLiveData.observe(this, new Observer<String>() {
        @Override
        public void onChanged(@Nullable String s) {
            mTextView.setText(s);
        }
    });

}

我一直在研究Android SDK平台,有點不清楚如何保存應用程序的狀態。 因此,考慮到'Hello,Android'示例的這種小型重新設計:

package com.android.hello;

import android.app.Activity;
import android.os.Bundle;
import android.widget.TextView;

public class HelloAndroid extends Activity {

  private TextView mTextView = null;

  /** Called when the activity is first created. */
  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    mTextView = new TextView(this);

    if (savedInstanceState == null) {
       mTextView.setText("Welcome to HelloAndroid!");
    } else {
       mTextView.setText("Welcome back.");
    }

    setContentView(mTextView);
  }
}

我認為這對於最簡單的情況就足夠了,但無論我如何離開應用程序,它總是會響應第一條消息。

我確信解決方案就像覆蓋onPause或類似的東西一樣簡單,但我已經在文檔中捅了大約30分鐘左右並且沒有找到任何明顯的東西。


onSaveInstanceState()用於瞬態數據(在onCreate() / onRestoreInstanceState()恢復), onPause()用於持久數據(在onResume()恢復)。 來自Android技術資源:

如果Activity被停止並且可能在恢復之前被殺死,則Android會調用onSaveInstanceState() !這意味著它應該存儲重新啟動Activity時重新初始化為相同條件所需的任何狀態。它與onCreate()方法相對應,實際上傳入onCreate()的savedInstanceState Bundle與onSaveInstanceState()方法中構造為outState的Bundle相同。

onPause()onResume()也是免費的方法。當Activity結束時總是調用onPause(),即使我們發起了這個(例如使用finish()調用)。我們將使用它將當前註釋保存回數據庫。好的做法是釋放在onPause()期間可以釋放的任何資源,以便在處於被動狀態時佔用更少的資源。


重新創建活動

在某些情況下,您的活動會因應用程序的正常行為而被銷毀,例如當用戶按下“返回”按鈕或您的活動通過調用finish()發出自己的破壞信號時。 如果系統當前已停止且未長時間使用或前台活動需要更多資源,系統也可能會破壞您的活動,因此系統必須關閉後台進程才能恢復內存。

當您的activity因用戶按下Back或activity自行完成而被銷毀時,系統對該Activity實例的概念將永遠消失,因為該行為表明不再需要該活動。 但是,如果系統因係統約束(而不是正常的應用程序行為)而破壞活動,那麼雖然實際的Activity實例已經消失,但係統會記住它存在,如果用戶導航回到它,系統會創建一個新的活動的實例,使用一組保存的數據來描述destroyed時的活動狀態。 系統用於恢復先前狀態的已保存數據稱為“實例狀態”,是存儲在Bundle對像中的鍵值對的集合。

要保存有關活動狀態的其他數據,必須覆蓋onSaveInstanceState()回調方法。 系統在用戶離開您的活動時調用此方法,並向其傳遞Bundle對象,該對象將在您的活動意外銷毀時保存。 如果系統必須稍後重新創建活動實例,它會將相同的Bundle對像傳遞給onRestoreInstanceState()onCreate()方法。

當系統開始停止活動時,它會調用onSaveInstanceState() (1),這樣您就可以指定要保存的其他狀態數據,以防必須重新創建Activity實例。 如果活動被銷毀並且必須重新創建相同的實例,則係統會將(1)中定義的狀態數據傳遞給onCreate()方法(2)和onRestoreInstanceState()方法(3)。

保存您的Activity狀態

當您的活動開始停止時,系統會調用onSaveInstanceState()以便您的活動可以使用一組鍵值對來保存狀態信息。 此方法的默認實現保存有關活動視圖層次結構狀態的信息,例如EditText小部件中的文本或ListView的滾動位置。

要保存活動的其他狀態信息,必須實現onSaveInstanceState()並將鍵值對添加到Bundle對象。 例如:

  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);
}

警告:始終調用onSaveInstanceState()的超類實現,以便默認實現可以保存視圖層次結構的狀態。

恢復您的Activity狀態

在先前銷毀活動之後重新創建活動時,您可以從系統傳遞活動的Bundle中恢復已保存的狀態。 onCreate()onRestoreInstanceState()回調方法都接收包含實例狀態信息的相同Bundle

因為無論系統是創建活動的新實例還是重新創建前一個實例,都會調用onCreate()方法,因此在嘗試讀取之前必須檢查狀態Bundle是否為null。 如果它為null,則係統正在創建活動的新實例,而不是恢復已銷毀的先前實例。

例如,以下是如何在onCreate()恢復某些狀態數據:

 @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
 }

 }

您可以選擇實現onRestoreInstanceState() ,系統在onStart()方法之後調用onRestoreInstanceState()而不是在onCreate()期間恢復狀態。 僅當存在要恢復的已保存狀態時,系統才會調用onRestoreInstanceState() ,因此您無需檢查Bundle是否為null:

  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);
}

Kotlin代碼:

保存:

override fun onSaveInstanceState(outState: Bundle) {
    super.onSaveInstanceState(outState.apply {
        putInt("intKey", 1)
        putString("stringKey", "String Value")
        putParcelable("parcelableKey", parcelableObject)
    })
}

然後在onCreate()onRestoreInstanceState()

    val restoredInt = savedInstanceState?.getInt("intKey") ?: 1 //default int
    val restoredString = savedInstanceState?.getString("stringKey") ?: "default string"
    val restoredParcelable = savedInstanceState?.getParcelable<ParcelableClass>("parcelableKey") ?: ParcelableClass() //default parcelable

如果您不想擁有Optionals,請添加默認值


同時我一般不再使用

Bundle savedInstanceState & Co

對於大多數活動而言,生活週期過於復雜且不必要。谷歌聲稱自己,它甚至不可靠。

我的方法是立即保存首選項中的任何更改

 SharedPreferences p;
 p.edit().put(..).commit()

在某種程度上,SharedPreferences的工作方式與Bundles類似。並且自然而且首先這些值必須是偏好的。

在復雜數據的情況下,您可以使用Sqlite而不是使用首選項。

應用此概念時,活動將繼續使用上次保存的狀態,無論它是初始打開還是重新啟動,或者由於後端堆棧而重新打開。


實現此更改基本上有兩種方法。

  1. 使用onSaveInstanceState()onRestoreInstanceState()
  2. 在清單中android:configChanges="orientation|screenSize"

我真的不建議使用第二種方法。因為在我的一次經驗中,它導致設備屏幕的一半在從縱向旋轉到橫向時變黑,反之亦然。

使用上面提到的第一種方法,我們可以在方向更改或任何配置更改發生時保留數據。我知道一種可以在savedInstance狀態對像中存儲任何類型數據的方法。

示例:如果要保留Json對象,請考慮一個案例。使用getter和setter創建一個模型類。

class MyModel extends Serializable{
JSONObject obj;

setJsonObject(JsonObject obj)
{
this.obj=obj;
}

JSONObject getJsonObject()
return this.obj;
} 
}

現在在onCreate和onSaveInstanceState方法的活動中執行以下操作。它看起來像這樣:

@override
onCreate(Bundle savedInstaceState){
MyModel data= (MyModel)savedInstaceState.getSerializable("yourkey")
JSONObject obj=data.getJsonObject();
//Here you have retained JSONObject and can use.
}


@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
//Obj is some json object 
MyModel dataToSave= new MyModel();
dataToSave.setJsonObject(obj);
oustate.putSerializable("yourkey",dataToSave); 

}

您需要覆蓋onSaveInstanceState(Bundle savedInstanceState)並將要更改的應用程序狀態值寫入Bundle參數,如下所示:

@Override
public void onSaveInstanceState(Bundle savedInstanceState) {
  super.onSaveInstanceState(savedInstanceState);
  // Save UI state changes to the savedInstanceState.
  // This bundle will be passed to onCreate if the process is
  // killed and restarted.
  savedInstanceState.putBoolean("MyBoolean", true);
  savedInstanceState.putDouble("myDouble", 1.9);
  savedInstanceState.putInt("MyInt", 1);
  savedInstanceState.putString("MyString", "Welcome back to Android");
  // etc.
}

Bundle本質上是一種存儲NVP(“名稱 - 值對”)映射的方式,它將被傳遞到onCreate()onRestoreInstanceState() ,在那裡你可以像這樣提取值:

@Override
public void onRestoreInstanceState(Bundle savedInstanceState) {
  super.onRestoreInstanceState(savedInstanceState);
  // Restore UI state from the savedInstanceState.
  // This bundle has also been passed to onCreate.
  boolean myBoolean = savedInstanceState.getBoolean("MyBoolean");
  double myDouble = savedInstanceState.getDouble("myDouble");
  int myInt = savedInstanceState.getInt("MyInt");
  String myString = savedInstanceState.getString("MyString");
}

您通常會使用此技術來存儲應用程序的實例值(選擇,未保存的文本等)。


我想我找到了答案。 讓我用簡單的話說出我的所作所為:

假設我有兩個活動,activity1和activity2,我從activity1導航到activity2(我已在activity2中完成了一些工作),再次通過單擊activity1中的按鈕返回到活動1。 現在在這個階段我想回到activity2,我想在上次離開activity2時看到我的activity2處於相同的狀態。

對於上面的場景,我所做的是在清單中我做了一些像這樣的更改:

<activity android:name=".activity2"
          android:alwaysRetainTaskState="true"      
          android:launchMode="singleInstance">
</activity>

在按鈕點擊事件的activity1中我做了這樣的事情:

Intent intent = new Intent();
intent.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
intent.setClassName(this,"com.mainscreen.activity2");
startActivity(intent);

在按鈕點擊事件的activity2中我做了這樣的事情:

Intent intent=new Intent();
intent.setClassName(this,"com.mainscreen.activity1");
startActivity(intent);

現在將會發生的事情是,我們在activity2中所做的任何更改都不會丟失,我們可以在與之前離開的狀態相同的狀態下查看activity2。

我相信這是答案,這對我來說很好。 如果我錯了,請糾正我。


當系統需要內存並殺死應用程序時,會調用onSaveInstanceState 。 用戶剛剛關閉應用程序時不會調用它。 所以我認為應用程序狀態也應該保存在onPause它應該保存到一些持久存儲器,如PreferencesSqlite


請注意,根據developer.android.com/reference/android/app/Activity.html有關活動狀態的文檔, 對於持久數據使用onSaveInstanceStateonRestoreInstanceState是不安全的。

該文件陳述(在“活動生命週期”部分):

請注意,將持久數據保存在onPause()而不是onSaveInstanceState(Bundle)非常重要,因為後者不是生命週期回調的一部分,因此不會在其文檔中描述的每種情況下調用。

換句話說,將持久數據的保存/恢復代碼放在onPause()onResume()

編輯 :為了進一步說明,這裡是onSaveInstanceState()文檔:

在活動可能被殺死之前調用此方法,以便在將來某個時間返回時它可以恢復其狀態。 例如,如果活動B在活動A前面啟動,並且在某些時候活動A被殺死以回收資源,活動A將有機會通過此方法保存其用戶界面的當前狀態,以便在用戶返回時對於活動A,可以通過onCreate(Bundle)onRestoreInstanceState(Bundle)恢復用戶界面的狀態。


這是Android開發的經典“問題”。 這裡有兩個問題:

  • 有一個微妙的Android Framework錯誤,它使開發過程中的應用程序堆棧管理變得非常複雜,至少在舊版本上是這樣(不完全確定是否/何時/如何修復)。 我將在下面討論這個錯誤。
  • 管理此問題的“正常”或預期方式本身相當複雜,具有onPause / onResume和onSaveInstanceState / onRestoreInstanceState的二元性

瀏覽所有這些線程,我懷疑開發人員大多數時間同時討論這兩個不同的問題......因此所有混淆和報告“這對我不起作用”。

首先,澄清“預期”行為:onSaveInstance和onRestoreInstance是脆弱的,僅適用於瞬態。 預期用途(afaict)用於在電話旋轉(方向改變)時處理活動娛樂。 換句話說,預期的用法是當您的Activity仍然在邏輯上“在頂部”時,但仍然必須由系統重新實例化。 保存的Bundle不會在進程/ memory / gc之外保留,因此如果您的活動進入後台,則無法真正依賴它。 是的,也許你的Activity的記憶將在它的背景之旅中存活並逃脫GC,但這不可靠(也不可預測)。

因此,如果您的某個場景中存在有意義的“用戶進度”或應該在應用程序的“啟動”之間保留的狀態,則指導是使用onPause和onResume。 您必須自己選擇並準備持久性商店。

但是 - 有一個非常混亂的錯誤使所有這一切變得複雜。 細節在這裡:

http://code.google.com/p/android/issues/detail?id=2373

http://code.google.com/p/android/issues/detail?id=5277

基本上,如果您的應用程序是使用SingleTask標誌啟動的,然後您從主屏幕或啟動器菜單啟動它,那麼後續調用將創建一個新任務...您將有效地擁有兩個不同的應用實例居住在同一堆棧中......這非常快速地變得非常奇怪。 當您在開發期間(即從Eclipse或Intellij)啟動應用程序時,這似乎會發生,因此開發人員會遇到這種情況。 但也通過一些應用程序商店更新機制(因此它也會影響您的用戶)。

在我意識到我的主要問題是這個錯誤,而不是預期的框架行為之前,我在這些線程中奮戰了幾個小時。 一個偉大的寫作和 解決方法 (更新:見下文)似乎來自用戶@kaciula在這個答案中:

主頁按鍵行為

更新2013年6月 :幾個月後,我終於找到了“正確”的解決方案。 您不需要自己管理任何有狀態的startupApp標記,您可以從框架中檢測到這一點並適當地保釋。 我在LauncherActivity.onCreate的開頭附近使用它:

if (!isTaskRoot()) {
    Intent intent = getIntent();
    String action = intent.getAction();
    if (intent.hasCategory(Intent.CATEGORY_LAUNCHER) && action != null && action.equals(Intent.ACTION_MAIN)) {
        finish();
        return;
    }
}

onSaveInstance當活動進入後台時,確實說明了callen

從文檔引用:“ onSaveInstanceState(Bundle)在將活動置於這樣的背景狀態之前調用該方法”


以下是Steve Moseley的答案(由ToolmakerSteve撰寫)的評論,該評論將事物置於透視中(在整個onSaveInstanceState vs onPause,east cost vs west cost saga)

@VVK - 我部分不同意。退出應用程序的某些方法不會觸發onSaveInstanceState(oSIS)。這限制了oSIS的有用性。它值得支持,用於最小的操作系統資源,但如果應用程序想要將用戶返回到他們所處的狀態,無論應用程序如何退出,都必須使用持久存儲方法。我使用onCreate來檢查bundle,如果它丟失了,那麼檢查 持久存儲。這集中了決策。我可以從崩潰,後退按鈕退出或自定義菜單項退出恢復,或者在很多天后回到屏幕用戶。 - ToolmakerSteve 2015年9月19日10:38


僅在旋轉屏幕(方向改變)時,onSaveInstanceState(bundle)onRestoreInstanceState(bundle)方法對於數據持久性是有用的。
他們不是在應用程序之間切換(因為即使是好的onSaveInstanceState()方法被調用,但onCreate(bundle)onRestoreInstanceState(bundle)沒有再次調用。
欲了解更多持久使用共享偏好。閱讀這篇文章


我的問題是我只在應用程序生命週期中需要持久性(即單個執行包括在同一個應用程序中啟動其他子活動並旋轉設備等)。我嘗試了上述答案的各種組合,但在所有情況下都沒有得到我想要的東西。最後,對我有用的是在onCreate期間獲取對savedInstanceState的引用:

mySavedInstanceState=savedInstanceState;

並在我需要時使用它來獲取變量的內容,類似於:

if (mySavedInstanceState !=null) {
   boolean myVariable = mySavedInstanceState.getBoolean("MyVariable");
}

我使用onSaveInstanceStateonRestoreInstanceState如上所述,但我想我也可以或者使用我的方法來保存變量(例如使用putBoolean


為了幫助減少樣板,我使用以下內容interfaceclass讀取/寫入以Bundle保存實例狀態。

首先,創建一個用於註釋實例變量的接口:

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({
        ElementType.FIELD
})
public @interface SaveInstance {

}

然後,創建一個類,其中將使用反射將值保存到包中:

import android.app.Activity;
import android.app.Fragment;
import android.os.Bundle;
import android.os.Parcelable;
import android.util.Log;

import java.io.Serializable;
import java.lang.reflect.Field;

/**
 * Save and load fields to/from a {@link Bundle}. All fields should be annotated with {@link
 * SaveInstance}.</p>
 */
public class Icicle {

    private static final String TAG = "Icicle";

    /**
     * Find all fields with the {@link SaveInstance} annotation and add them to the {@link Bundle}.
     *
     * @param outState
     *         The bundle from {@link Activity#onSaveInstanceState(Bundle)} or {@link
     *         Fragment#onSaveInstanceState(Bundle)}
     * @param classInstance
     *         The object to access the fields which have the {@link SaveInstance} annotation.
     * @see #load(Bundle, Object)
     */
    public static void save(Bundle outState, Object classInstance) {
        save(outState, classInstance, classInstance.getClass());
    }

    /**
     * Find all fields with the {@link SaveInstance} annotation and add them to the {@link Bundle}.
     *
     * @param outState
     *         The bundle from {@link Activity#onSaveInstanceState(Bundle)} or {@link
     *         Fragment#onSaveInstanceState(Bundle)}
     * @param classInstance
     *         The object to access the fields which have the {@link SaveInstance} annotation.
     * @param baseClass
     *         Base class, used to get all superclasses of the instance.
     * @see #load(Bundle, Object, Class)
     */
    public static void save(Bundle outState, Object classInstance, Class<?> baseClass) {
        if (outState == null) {
            return;
        }
        Class<?> clazz = classInstance.getClass();
        while (baseClass.isAssignableFrom(clazz)) {
            String className = clazz.getName();
            for (Field field : clazz.getDeclaredFields()) {
                if (field.isAnnotationPresent(SaveInstance.class)) {
                    field.setAccessible(true);
                    String key = className + "#" + field.getName();
                    try {
                        Object value = field.get(classInstance);
                        if (value instanceof Parcelable) {
                            outState.putParcelable(key, (Parcelable) value);
                        } else if (value instanceof Serializable) {
                            outState.putSerializable(key, (Serializable) value);
                        }
                    } catch (Throwable t) {
                        Log.d(TAG, "The field '" + key + "' was not added to the bundle");
                    }
                }
            }
            clazz = clazz.getSuperclass();
        }
    }

    /**
     * Load all saved fields that have the {@link SaveInstance} annotation.
     *
     * @param savedInstanceState
     *         The saved-instance {@link Bundle} from an {@link Activity} or {@link Fragment}.
     * @param classInstance
     *         The object to access the fields which have the {@link SaveInstance} annotation.
     * @see #save(Bundle, Object)
     */
    public static void load(Bundle savedInstanceState, Object classInstance) {
        load(savedInstanceState, classInstance, classInstance.getClass());
    }

    /**
     * Load all saved fields that have the {@link SaveInstance} annotation.
     *
     * @param savedInstanceState
     *         The saved-instance {@link Bundle} from an {@link Activity} or {@link Fragment}.
     * @param classInstance
     *         The object to access the fields which have the {@link SaveInstance} annotation.
     * @param baseClass
     *         Base class, used to get all superclasses of the instance.
     * @see #save(Bundle, Object, Class)
     */
    public static void load(Bundle savedInstanceState, Object classInstance, Class<?> baseClass) {
        if (savedInstanceState == null) {
            return;
        }
        Class<?> clazz = classInstance.getClass();
        while (baseClass.isAssignableFrom(clazz)) {
            String className = clazz.getName();
            for (Field field : clazz.getDeclaredFields()) {
                if (field.isAnnotationPresent(SaveInstance.class)) {
                    String key = className + "#" + field.getName();
                    field.setAccessible(true);
                    try {
                        Object fieldVal = savedInstanceState.get(key);
                        if (fieldVal != null) {
                            field.set(classInstance, fieldVal);
                        }
                    } catch (Throwable t) {
                        Log.d(TAG, "The field '" + key + "' was not retrieved from the bundle");
                    }
                }
            }
            clazz = clazz.getSuperclass();
        }
    }

}

用法示例:

public class MainActivity extends Activity {

    @SaveInstance
    private String foo;

    @SaveInstance
    private int bar;

    @SaveInstance
    private Intent baz;

    @SaveInstance
    private boolean qux;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Icicle.load(savedInstanceState, this);
    }

    @Override
    public void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        Icicle.save(outState, this);
    }

}

注意:此代碼改編自名為AndroidAutowire的庫項目,該項目根據MIT許可證獲得許可


直接回答原始問題。savedInstancestate為null,因為永遠不會重新創建Activity。

只有在以下情況下,才會使用州捆綁包重新創建您的活動:

  • 配置更改,例如更改方向或電話語言,這可能需要創建新的活動實例。
  • 操作系統銷毀活動後,您將從後台返回應用程序。

Android會在內存壓力下或在長時間處於後台後銷毀後台活動。

在測試hello world示例時,有幾種方法可以離開並返回Activity。

  • 當您按後退按鈕時,活動結束。重新啟動應用程序是一個全新的實例。你根本沒有從後台恢復。
  • 當您按主頁按鈕或使用任務切換器時,活動將進入後台。導航回應用程序時,只有在必須銷毀活動時才會調用onCreate。

在大多數情況下,如果您只是按下主頁然後再次啟動應用程序,則無需重新創建活動。它已經存在於內存中,因此不會調用onCreate()。

“設置” - >“開發者選項”下有一個名為“不要保留活動”的選項。當它啟用時,Android將始終銷毀活動並在它們背景時重新創建它們。這是在開發時保持啟用的一個很好的選項,因為它模擬了最壞的情況。(低內存設備一直在回收您的活動)。

其他答案是有價值的,因為他們教你正確的存儲狀態的方法,但我不覺得他們真的回答為什麼你的代碼沒有以你預期的方式工作。


簡單快速解決這個問題就是使用Icepick

首先,設置庫 app/build.gradle

repositories {
  maven {url "https://clojars.org/repo/"}
}
dependencies {
  compile 'frankiesardo:icepick:3.2.0'
  provided 'frankiesardo:icepick-processor:3.2.0'
}

現在,讓我們查看下面的示例如何在Activity中保存狀態

public class ExampleActivity extends Activity {
  @State String username; // This will be automatically saved and restored

  @Override public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    Icepick.restoreInstanceState(this, savedInstanceState);
  }

  @Override public void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);
    Icepick.saveInstanceState(this, outState);
  }
}

它適用於活動,碎片或任何需要在Bundle上序列化其狀態的對象(例如迫擊砲的ViewPresenters)

Icepick還可以為自定義視圖生成實例狀態代碼:

class CustomView extends View {
  @State int selectedPosition; // This will be automatically saved and restored

  @Override public Parcelable onSaveInstanceState() {
    return Icepick.saveInstanceState(this, super.onSaveInstanceState());
  }

  @Override public void onRestoreInstanceState(Parcelable state) {
    super.onRestoreInstanceState(Icepick.restoreInstanceState(this, state));
  }

  // You can put the calls to Icepick into a BaseCustomView and inherit from it
  // All Views extending this CustomView automatically have state saved/restored
}




application-state