web-dev-qa-db-ja.com

onSaveInstanceState()およびonRestoreInstanceState()

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

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

134
BlaBRA

通常、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");
  }
}

ビューステートは保存されるため、保存する必要はありません 自動的に super.onSaveInstanceState(icicle);を呼び出します。

187
Robert

onRestoreInstanceState()が呼び出されます再作成時のみ OSによるkilledの後のアクティビティ。このような状況は次の場合に発生します。

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

対照的に、アクティビティ中にデバイスのBackボタンを押すと、アクティビティはfinish()ed(つまり、デスクトップアプリケーションの終了と考えられます)になり、次回アプリを起動すると「新鮮」に開始されます。 Backをヒットしたときに意図的に終了したため、保存された状態はありません。

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

全体として、onRestoreInstanceState()のドキュメントに記載されているとおり:

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

私が読んだように:Activityをサブクラス化していて、誰かがあなたのサブクラスをサブクラス化することが予想されない限り、onRestoreInstanceState()をオーバーライドする理由はありません。

147
Ognyan

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

7

回避策として、アクティビティ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.

もう1つのアイデアは、アクティビティ状態を保存するリポジトリクラスを作成し、各アクティビティがそのクラスを参照するようにすることです(シングルトン構造を使用することも可能です)。

4
sotrh

OnSaveInstanceStateは、別のアクティビティが前面に来ると常に呼び出されることがわかりました。 onStopも同様です。

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

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

図2 これについて説明します。

3
buzz

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

3
user1771286

このスレッドはかなり古いと思います。 onSaveInstanceState()も呼び出される別のケースに言及しますが、それはActivity.moveTaskToBack(boolean nonRootActivity)を呼び出すときです。

2
macio.Jun

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

1
Rajkiran

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

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

1

私はそのようにすることができます(_#Javaではなくc#ですが、それは問題ではありません...):

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
}
0
EDynamic90

私はこれに偶然遭遇し、ドキュメントに私の答えがあったことに気づいていました:

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

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

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

0
Ben Scannell

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

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

0
elvitucho