onSaveInstanceState()およびonRestoreInstanceState()


138

ActivityメソッドonSaveInstanceState()とを使用して、状態を保存および復元しようとしていますonRestoreInstanceState()

問題は、onRestoreInstanceState()メソッドに入らないことです。これがなぜであるか誰かが私に説明できますか?


1
@Nitin:リンクを共有してくれてありがとう...これは私にとっていくつかのことを解決しました+1
Taliadon

2
@NitinBansalリンクが死んでいる。
ashishdhiman2007

回答:


191

通常はで状態を復元しますonCreate()。それを復元することも可能ですonRestoreInstanceState()が、あまり一般的ではありません。(onRestoreInstanceState()は後onStart()に呼び出されますが、onCreate()は前に呼び出されonStart()ます。

putメソッドを使用して値を格納しますonSaveInstanceState()

protected void onSaveInstanceState(Bundle icicle) {
  super.onSaveInstanceState(icicle);
  icicle.putLong("param", value);
}

の値を復元しますonCreate()

public void onCreate(Bundle icicle) {
  if (icicle != null){
    value = icicle.getLong("param");
  }
}

2
問題は、startActivityを使用してアクティビティAに戻ることです。アクティビティBに戻ると、オブジェクトは空のつららになります。
BlaBRA 2010年

5
私が正しく理解していれば、これはあなたがしていることです:BからstartActivity(A)を呼び出します。次に、Aからfinish()を呼び出してBに戻ります。その場合、最初のアクティビティBは破棄されず、onCreate()もonRestoreInstanceState()も呼び出されません。これらのメソッドは、必要な場合にのみ呼び出されます。つまり、アクティビティが破棄され、システムで再作成する必要がある場合です。
ロバート

4
最初のアクティビティBは、メモリ不足のために破壊される可能性があることを付け加えておきます。これにより、onCreateおよびonRestoreInstanceStateがトリガーされます。
ロバート

1
erikb、はい、アクティビティBが再開されます。または、OSがそれを再要求し、再作成してから再開した場合。
Robert


149

onRestoreInstanceState()OSによって強制終了さた後にアクティビティを再作成する場合にのみ呼び出されます。このような状況は次の場合に発生します。

  • デバイスの向きが変わります(アクティビティが破棄され、再作成されます)。
  • あなたの前に別のアクティビティがあり、ある時点でOSがメモリを解放するためにアクティビティを強制終了します(たとえば)。次回アクティビティを開始すると、onRestoreInstanceState()が呼び出されます。

対照的に、アクティビティBackにいてデバイスのボタンを押すと、アクティビティはfinish()ed(つまり、デスクトップアプリケーションの終了と見なされます)となり、次にアプリを起動したときに、「フレッシュ」、つまりを押したときに意図的に終了したため、保存された状態Back

他の混乱の原因は、アプリが別のアプリにフォーカスを失うonSaveInstanceState()と呼び出されますが、アプリに戻るときonRestoreInstanceState()に呼び出されない可能性があることです。これは、元の質問で説明されているケースです。つまり、アクティビティがonRestoreInstanceState()ほとんど「生きている」ため、他のアクティビティが前にあった期間にアクティビティが中止されなかった場合は呼び出されません。

全体として、次のドキュメントに記載されていますonRestoreInstanceState()

ほとんどの実装では、単にonCreate(Bundle)を使用して状態を復元しますが、初期化がすべて完了した後、またはサブクラスがデフォルトの実装を使用するかどうかを決定できるようにするために、ここで実行すると便利な場合があります。このメソッドのデフォルトの実装は、onSaveInstanceState(Bundle)によって以前にフリーズされたビューステートの復元を実行します。

私が読んだとおり:onRestoreInstanceState()サブクラス化Activityしていない限りオーバーライドする理由はなく、誰かがサブクラスをサブクラス化することが期待されています。


3
ええ、これは正しいようですが、それはひどいです。別のアクティビティからアクティビティに戻るときにも実行する必要があります。これが必要な状況はたくさんあります。
masi

4
@masiユーザーが(別のアクティビティから)アクティビティに戻ったときに、Activityで他のメソッドが既に呼び出されています。onSave / RestoreInstanceState()は、別の特定の目的で使用されます。
superjos 2012年

8

保存した状態onSaveInstanceState()は、後でonCreate()メソッドを呼び出すときに使用できます。を使用してonCreate(およびそのBundleパラメーター)アクティビティの状態を復元します。


4

回避策として、アクティビティAを開始するために使用するインテントに維持したいデータを含むバンドルを保存できます。

Intent intent = new Intent(this, ActivityA.class);
intent.putExtra("bundle", theBundledData);
startActivity(intent);

アクティビティAは、これをアクティビティBに返す必要があります。アクティビティBのonCreateメソッドでインテントを取得します。

Intent intent = getIntent();
Bundle intentBundle;
if (intent != null)
    intentBundle = intent.getBundleExtra("bundle");
// Do something with the data.

別のアイデアは、アクティビティーの状態を格納するリポジトリー・クラスを作成し、各アクティビティーがそのクラスを参照するようにすることです(シングルトン構造を使用することもできます)。


3

主なものは、あなたがに格納しない場合ということですonSaveInstanceState()その後、onRestoreInstanceState()呼び出されません。これが主な違いであるrestoreInstanceState()onCreate()。本当に何かを保管してください。おそらくこれはあなたの問題です。


1
onRestoreInstanceState()は、OnSaveInstanceState()に何も保存しない場合でも呼び出されます
abh22ishek

3

別のアクティビティがフォアグラウンドになると、onSaveInstanceStateが常に呼び出されることがわかりました。そしてonStopも同様です。

ただし、onRestoreInstanceStateが呼び出されたのは、onCreateおよびonStartも呼び出された場合のみです。また、onCreateとonStartが常に呼び出されるとは限りませんでした。

そのため、アクティビティがバックグラウンドに移動しても、Androidが常に状態情報を削除するとは限りません。ただし、安全のために状態を保存するためにライフサイクルメソッドを呼び出します。したがって、状態が削除されない場合、Androidはライフサイクルメソッドを必要としないため、それらを呼び出して状態を復元しません。

図2はこれを説明しています。


2

このスレッドはかなり古いと思います。別のケースについても触れておきonSaveInstanceState()ますActivity.moveTaskToBack(boolean nonRootActivity)。これは、が呼び出されたときにも呼び出されます。


1

android:configChanges="orientation|screenSize"およびonConfigurationChanged(Configuration newConfig)でアクティビティの向きの変更を処理している場合は、onRestoreInstanceState()呼び出されません。


1

onRestoreInstanceStateが常にonSaveInstanceStateの後に呼び出される必要はありません。

注:onRestoreInstanceStateは、アクティビティが回転したとき(向きが処理されていないとき)に呼び出されるか、アクティビティを開いてから他のアプリを開いて、OSによってアクティビティインスタンスがメモリからクリアされるようにします。


1

ドキュメントから、保存されたインスタンスの状態を使用してアクティビティのUI状態を復元すると、次のように示されます。

onCreate()中に状態を復元する代わりに、システムがonStart()メソッドの後に呼び出すonRestoreInstanceState()の実装を選択できます。システムがonRestoreInstanceState()を呼び出すのは、復元する保存済みの状態がある場合のみなので 、バンドルがnullであるかどうかを確認する必要はありません

ここに画像の説明を入力してください

ここに画像の説明を入力してください

IMO、これはonCreateでこれをチェックするよりも明確な方法であり、単一の責任の原則によりよく適合します。


0

私の場合、onRestoreInstanceStateデバイスの向きを変更した後にアクティビティが再構築されたときに呼び出されました。onCreate(Bundle)が最初に呼び出されましたが、バンドルには私が設定したキー/値がありませんでしたonSaveInstanceState(Bundle)

直後に、onRestoreInstanceState(Bundle)正しいキー/値を持つバンドルで呼び出されました。


0

私はこれに遭遇し、ドキュメントに私の答えがあることに気づきました:

「この関数がnull状態で呼び出されることはありません。」

https://developer.android.com/reference/android/view/View.html#onRestoreInstanceState(android.os.Parcelable)

私の場合、最初のインスタンス化でonRestoreInstanceStateが呼び出されなかったのはなぜかと思っていました。これは、何も保存しない場合、ビューを再構築するときに呼び出されないことも意味します。


0

私はそのようにすることができます(申し訳ありませんがc#ではなくjavaですが問題ではありません...):

private int iValue = 1234567890;

function void MyTest()
{
    Intent oIntent = new Intent (this, typeof(Camera2Activity));
    Bundle oBundle = new Bundle();
    oBundle.PutInt("MYVALUE", iValue); //=> 1234567890
    oIntent.PutExtras (oBundle);
    iRequestCode = 1111;
    StartActivityForResult (oIntent, 1111);
}

そしてあなたの活動のために

private int iValue = 0;

protected override void OnCreate(Bundle bundle)
{
    Bundle oBundle =  Intent.Extras;
    if (oBundle != null)
    {
        iValue = oBundle.GetInt("MYVALUE", 0);
        //=>1234567890
    }
}

private void FinishActivity(bool bResult)
{
    Intent oIntent = new Intent();
    Bundle oBundle = new Bundle();
    oBundle.PutInt("MYVALUE", iValue);//=>1234567890
    oIntent.PutExtras(oBundle);
    if (bResult)
        {
            SetResult (Result.Ok, oIntent);
        }
    else
        SetResult(Result.Canceled, oIntent);
    GC.Collect();
    Finish();
}

最後に

protected override void OnActivityResult(int iRequestCode, Android.App.Result oResultCode, Intent oIntent)
{
    base.OnActivityResult (iRequestCode, oResultCode, oIntent);
    iValue = oIntent.Extras.GetInt("MYVALUE", -1); //=> 1234567890
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.