Activityのリビルドとリカバリ

6282 ワード

Activityの再構築については、次の3つの側面から理解できます.

Activityでは、再構築の3つの状況が発生します。


1.システムメモリ不足:androidシステムはプロセスを殺し、システムがメモリを解放する必要がある場合、プロセス内にあるactivityは破棄されます.ユーザーがこのActivityに戻ると、このActivityは再構築されます.
2.Configuration Change(Activity縦画面切り替え、マルチウィンドウモードに入る):縦画面切り替えの場合、システムはレイアウトを調整して新しい構成に適応するため、デフォルトでActivityを再構築します.
3.Activityを呼び出すoncreate()メソッド:トピック切り替え時にoncreateを呼び出してActivityを再構築し、新しいトピックを有効にします.

Activityの再構築時の状態変化:


まず、簡単なコードで、再構築プロセスActivityの状態を見てみましょう.
public class LifeCycleActivity extends AppCompatActivity {

    private static final String TAG = LifeCycleActivity.class.getName();

    private static final String KEY_TEST = "test";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_life_cycle);
        TextView tvContent = findViewById(R.id.tv_content);
        if (savedInstanceState == null) {
            Log.i(TAG, " ---> first time onCreate");
        } else {
            Log.i(TAG, " ---> recreate");
            String test = savedInstanceState.getString(KEY_TEST);
            tvContent.setText(test);
        }

        findViewById(R.id.btn_start).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                recreate();
            }
        });
    }

    @Override
    protected void onStart() {
        super.onStart();
        Log.i(TAG, " ---> onStart");
    }

    @Override
    protected void onResume() {
        super.onResume();
        Log.i(TAG, " ---> onResume");
    }

    @Override
    protected void onPause() {
        super.onPause();
        Log.i(TAG, " ---> onPause");
    }

    @Override
    protected void onStop() {
        super.onStop();
        Log.i(TAG, " ---> onStop");
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        Log.i(TAG, " ---> onDestory");
    }

    @Override
    protected void onRestart() {
        super.onRestart();
        Log.i(TAG, " ---> onRestart");
    }

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        outState.putString(KEY_TEST, "testing");
        Log.i(TAG," ---> onSaveInstanceState");
    }

    @Override
    protected void onRestoreInstanceState(Bundle savedInstanceState) {
        super.onRestoreInstanceState(savedInstanceState);
        String test = savedInstanceState.getString(KEY_TEST);
        Log.i(TAG, " ---> onRestoreInstanceState");
    }
}

App実行後に縦横画面を切り替え、上のコード実験で得られた結果は:
I/com.zj.activitylifecycle.LifeCycleActivity:  ---> first time onCreate I/com.zj.activitylifecycle.LifeCycleActivity:  ---> onStart I/com.zj.activitylifecycle.LifeCycleActivity:  ---> onResume I/com.zj.activitylifecycle.LifeCycleActivity:  ---> onPause I/com.zj.activitylifecycle.LifeCycleActivity:  ---> onSaveInstanceState I/com.zj.activitylifecycle.LifeCycleActivity:  ---> onStop I/com.zj.activitylifecycle.LifeCycleActivity:  ---> onDestory I/com.zj.activitylifecycle.LifeCycleActivity:  ---> recreate I/com.zj.activitylifecycle.LifeCycleActivity:  ---> onStart I/com.zj.activitylifecycle.LifeCycleActivity:  ---> onRestoreInstanceState I/com.zj.activitylifecycle.LifeCycleActivity:--->onResumeはpaused状態に入るとonSaveInstanceStateを呼び出して必要なデータ状態を保存し、再構築時にonCreateとonRestoreInstanceStateのパラメータで破棄前に保存したデータを取得できます.

Activityの状態回復


いくつかのシーンでは、あなたのActivityは正常に破棄され、ユーザーが戻るキーを押すか、Activity内部でfinish()メソッドを呼び出すと、ユーザーとシステムの観念の中でこのActivityのインスタンスはもう必要ありません.これらのシーンでActivityの破棄は、他の追加作業をする必要はありません.しかし、システムがActivityを破棄するのは、システムの制約(configurationおよびmemory pressure)によるものであり、この場合、ユーザのユーザ体験を維持するためには、ユーザがActivityに戻ったときにActivityの状態を回復する必要がある.この場合、Activityのインスタンスは消えていますが、Activityのインスタンスが存在したことを覚えています.ユーザーがActivityに戻ろうとすると、Activityが破棄されたときに保存した状態とデータを使用して、新しいActivityインスタンスが作成されます.
システムが以前の状態を復元するために保存したデータをinstance stateといい、Bundleに格納されたキー値ペアの集合である.デフォルトでは、Bundleを使用してlayoutのViewの状態(例えばEditTextに入力された情報)を格納し、Activityの再構築時に以前の状態に戻ることを保証します.また、メンバー変数の値やユーザーの進捗情報など、再構築時にリカバリしたい情報を格納することもできます.
ps:ActivityのViewの状態を復元できるように、各Viewには独自のidが必要です(android:idプロパティ定義).
しかし、Bundleは大量のデータを保存するのに適していません.データは保存時にメインスレッドにシーケンス化する必要があり、システムメモリを消費します.比較的多くのデータを保存する必要がある場合は、ローカルストレージと組み合わせることができます.
Viewのステータスシステムは自動的に保存されます.追加する必要はありませんが、他のデータを保存する必要がある場合はonSaveInstanceStateメソッドを書き換えることができます.
@Override
protected void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);
    outState.putString(KEY_TEST, "testing");
    Log.i(TAG," ---> onSaveInstanceState");
}

データはonCreateまたはonRestoreInstanceStateで復元されます.
@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_life_cycle);
        TextView tvContent = findViewById(R.id.tv_content);
        if (savedInstanceState == null) {
            Log.i(TAG, " ---> first time onCreate");
        } else {
            Log.i(TAG, "recreate");
            String test = savedInstanceState.getString(KEY_TEST);
            tvContent.setText(test);
        }

        findViewById(R.id.btn_start).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {

                recreate();
//                Intent intent = new Intent(LifeCycleActivity.this, SecondActivity.class);
//                startActivity(intent);

            }
        });

    }
@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
    super.onRestoreInstanceState(savedInstanceState);
    String test = savedInstanceState.getString(KEY_TEST);
    Log.i(TAG, "onRestoreInstanceState");
}

onSaveInstanceメソッドは、onPauseの後に呼び出されるたびに呼び出されるわけではありません.Activityが明確なclose(ユーザーが戻るボタンをクリック)またはfinishを呼び出す場合、onSaveInstanceStateは呼び出されません.
preferenceやdatabaseに保存するなど、データを永続化する必要がある場合は、Activityがフロントにいるときに保存するのが最適です.このような機会がなければ、onStopメソッドで保存することができます.