Androidコンポーネントシリーズ---Activity保存状態


このエッセイでは、Activityの保存状態の概念、すなわちsaving activity stateについて詳しく説明します.
一、Activity状態保持概念
Activityの状態を保存することは非常に重要です.例えば、私たちがゲームをしている間に、突然電話が来ました.この時、電話に出た後、私たちはゲームに戻りました.この時、私たちはゲームが前の進捗状況だったか、突発的な事件が発生したか、ゲームというアプリケーションが閉鎖されたことを望んでいます.この時、私たちがゲームを再開すれば、私たちはまだ前の進捗に戻りたいなら、その状態を保存する必要があります.これにより、Activityが破壊されたとき、保存された状態に応じて前の進捗に戻ることができます.これがActivityの状態保存です.
二、両方式の場合Activityの状態が保存されます
Activityの状態が保存されるには通常2つの方法がありますが、まずandroidの公式ドキュメントで提供されている図を見てみましょう.
1.あるActivityが別のActivityの前にあるとき、つまりもう一つのActivityがstop状態であるとき、このActivityは依然としてメモリを占有しており、Activityの状態を保持している.このときに後退ボタンをクリックすると、最初のActivityは再びフロントインタフェースに戻り、このActivityは元の状態を維持する.私たちはその状態を再獲得する必要はありません.
2.このActivityがstop状態でバックグラウンドにある場合、優先度の高いActivityがリソースを取得する必要がある場合、stop状態のActivityを破壊し、メモリを回収する可能性があります.このActivityオブジェクトはdestroyedされます.このとき、ActiveInstanceState()メソッドを呼び出してActivityのオブジェクトステータスを保存する必要があります.
onSaveInstanceState(Bundle outState)この方法はBundleタイプパラメータを受け入れ、BundleのputString、putIntメソッドによって保存する必要がある状態を保存することができます.
私たちのActivityが破壊されやすい場合、onSaveInstancesState()メソッドが呼び出されます.このとき、システムがこのActivityのスレッドを殺し、このActivityオブジェクトがdestroyされた後、このActivityを開くと、このActivityが再作成されます.このときシステムはonSaveInstanceStateメソッドのBundleオブジェクトをActivityのonCreate()メソッドとonRestoreInstanceState()メソッドに渡します.
どちらの方法でも、以前に保存したBundleオブジェクトに基づいてActivity以前の状態を復元できます.
三、onSaveInstanceState方法
protected void onSaveInstanceState (Bundle outState)

次に、この方法を具体的に見てみましょう.この方法では、Activityが殺されたときに、将来このActivityを再作成するときに保存された状態を回復することができます.このメソッドとActivityライフサイクル関数メソッドの呼び出し時期を疑う必要はありません.例えばonPause()メソッドでは、Activityがバックグラウンドにある場合や破壊されやすい場合に呼び出されます.
このonSaveInstanceStateメソッドは呼び出されない場合があります.
①activity Bはactivity Aの前にあります.このときBackボタンをクリックすると、activity BはonPause、onStopメソッドをそれぞれ呼び出します.この場合、onSaveInstanceState()メソッドは呼び出されません.この場合、私たちが表示しているactivity Bを閉じるので、onSaveInstanceState()の呼び出しは不要と考えられます.
②activity Bはactivity Aの前にあり、このときactivity Aはバックグラウンド状態であるがメモリリソースを占有しており、Backボタンによりactivity Aを再びフロントに戻す場合、onSaveInstanceState()メソッドも呼び出す必要がない.なぜなら、activity A自体が現在の状態を完全に保存しているからである.
 
次に、ActivityのonSaveInstanceState()、onCreate()およびonRestoreInstanceState()メソッドの呼び出しによってActivityの状態を維持する例を示します.
public class ThirdActivity extends Activity
{    private final String TAG = "ThirdActivity";    private Button button;
    @Override    protected void onCreate(Bundle savedInstanceState)
    {        super.onCreate(savedInstanceState);
        setContentView(R.layout.third);
        Log.i(TAG, "ThirdActivity onCreate");        
        if(savedInstanceState != null)
        {
            String name = (String)savedInstanceState.getString("name");
            Toast.makeText(ThirdActivity.this, "onCreate --->  " + name, 1).show();
        }
        
        button = (Button)findViewById(R.id.button);
        button.setOnClickListener(new OnClickListener()
        {
            @Override            public void onClick(View view)
            {
                Intent intent = new Intent();
                intent.setClass(ThirdActivity.this, FourthActivity.class);
                startActivity(intent);
            }
        });
        
    }
    
    @Override    protected void onStart()
    {        super.onStart();
        Log.i(TAG, "ThirdActivity onStart");
    }
    
    @Override    protected void onResume()
    {        super.onResume();
        Log.i(TAG, "ThirdActivity onResume");
    }
    
    @Override    protected void onPause()
    {        super.onPause();
        Log.i(TAG, "ThirdActivity onPause");
    }
    
    @Override    protected void onSaveInstanceState(Bundle outState)
    {        super.onSaveInstanceState(outState);
        Log.i(TAG, "ThirdActivity onSaveInstanceState");
        outState.putString("name", "xiaoluo");
    }
    
    @Override    protected void onRestoreInstanceState(Bundle savedInstanceState)
    {        super.onRestoreInstanceState(savedInstanceState);
        Log.i(TAG, "ThirdActivity onRestoreInstanceState");        if(savedInstanceState != null)
        {
            String name = (String)savedInstanceState.getString("name");
            Toast.makeText(ThirdActivity.this, "onRestoreInstanceState ---> " + name, 1).show();
        }
    }
    
    @Override    protected void onStop()
    {        super.onStop();
        Log.i(TAG, "ThirdActivity onStop");
    }
    
    @Override    protected void onRestart()
    {        super.onRestart();
        Log.i(TAG, "ThirdActivity onRestart");
    }
    
    @Override    protected void onDestroy()
    {        super.onDestroy();
        Log.i(TAG, "ThirdActivity onDestroy");
    }
}

このActivityでは、onSaveInstanceState()、onCreate()およびonRestoreInstanceState()メソッドを実装し、onSaveInstanceState()メソッドで現在のActivityの状態を保存します.
    @Override    protected void onSaveInstanceState(Bundle outState)
    {        super.onSaveInstanceState(outState);
        Log.i(TAG, "ThirdActivity onSaveInstanceState");
        outState.putString("name", "xiaoluo");
    }

次に、onCreate()メソッドとonRestoreInstanceState()メソッドで保存されたBundleオブジェクトを取得しようとします.Activityが初めて作成されたとき、onCreate()メソッドとonRestoreInstanceState()メソッドのBundleオブジェクトはnullです.
protected void onCreate(Bundle savedInstanceState)
    {        super.onCreate(savedInstanceState);
        setContentView(R.layout.third);
        Log.i(TAG, "ThirdActivity onCreate");        
        if(savedInstanceState != null)
        {
            String name = (String)savedInstanceState.getString("name");
            Toast.makeText(ThirdActivity.this, "onCreate --->  " + name, 1).show();
        }
        
        button = (Button)findViewById(R.id.button);
        button.setOnClickListener(new OnClickListener()
        {
            @Override            public void onClick(View view)
            {
                Intent intent = new Intent();
                intent.setClass(ThirdActivity.this, FourthActivity.class);
                startActivity(intent);
            }
        });
        
    }
@Override    protected void onRestoreInstanceState(Bundle savedInstanceState)
    {        super.onRestoreInstanceState(savedInstanceState);
        Log.i(TAG, "ThirdActivity onRestoreInstanceState");        if(savedInstanceState != null)
        {
            String name = (String)savedInstanceState.getString("name");
            Toast.makeText(ThirdActivity.this, "onRestoreInstanceState ---> " + name, 1).show();
        }
    }

この2つの方法でそれぞれToastのポップアップボックスを使用して、Bundleが保存している状態値を印刷できるかどうかを確認します.この実験をシミュレートするためには,携帯電話の画面の縦横を切り替える必要がある.
画面の方向が変更されると、まずdestroyとrecreateというActivityオブジェクトが私たちが構成したリソースファイルに基づいてインタフェースを再ロードします.このとき、私たちのActivityの状態を保存することは非常に重要です.多くの場合、画面の安心した変更はよくあることです.だからこの時、私たちはonSaveInstanceState()メソッドでActivityの状態を保存しなければなりません.
実験結果を見てみましょう
画面を反転すると、以前にonSaveInstanceState()メソッドでActivityの状態が保存されていたため、Activityがdestroyからrecreateに移行すると、保存したBundleオブジェクトがonCreateメソッドとonRestoreInstanceStateメソッドに渡され、Activityの状態を回復できるようになりました.
四、Android ViewコントロールのonSaveInstanceState()方法
Activityオブジェクトを作成するときに、親のonSaveInstanceState()メソッドを書き換えていない場合は、親のActivityのデフォルトのonSaveInstanceState()メソッドを呼び出すことで、Activityステータスの一部も保存されます.特に、親のonSaveInstanceState()メソッドは、レイアウトファイル内の各Viewオブジェクトの対応するonSaveInstanceState()メソッドを呼び出して、それぞれのステータスを維持します.AndroidのほとんどのwidgetコントロールはonSaveInstancesState()メソッドを非常によく実現しているので、これらの空間の値の変更は自動的に保存されます.たとえば、EditText、Checkboxコントロールは、Activityがdestroy-->recreateによって入力された場合でも、Viewコントロールの状態を保存する必要がある場合は、一意の識別子を指定する必要があります(android:idプロパティで指定します).指定がなければ、システムはその状態を保存しません.たとえば、次の例を見てみましょう.
    
        
        
        
        
        
        

このActivityのインタフェースには5つのViewコントロールがあります.ここでusernameというEditTextはIDを指定しています.emailというEditTextはIDを指定していません.次の3つのCheckBoxは、最後のCheckBoxだけがIDを指定していません.このActivityが再作成されると、各Viewコントロールの状態が保存されますか.
2つのテキストボックスに値を入力し、3つのCheckBoxをチェックします.画面を反転します.
usernameというEditTextと最初の2つのCheckBoxにIDを指定したため、システムはonSaveInstanceState()メソッドを呼び出してViewコントロールの状態を保存しますが、emailというEditTextと最後のCheckBoxについてはID識別子を指定していないので、システムは自動的にステータスを保存しません.
注意:デフォルトのActivityのonSaveInstanceState()メソッドでは、Viewコントロールのステータスが保存されますが、onSaveInstanceState()メソッドを再作成して、onCreate()メソッド、onSaveInstanceState()メソッド、onRestoreInstanceState()メソッドをそれぞれ書き換える場合は、まず親メソッドを呼び出すことをお勧めします.これにより、Viewコントロールのステータスがデフォルトで保存されます.
最後に、onSaveInstanceState()メソッドでは必ず呼び出されることは保証されませんので、onSaveInstanceState()メソッドではActivityの一時的なステータス情報しか保存できませんが、保存するオブジェクトやステータスを永続化するにはonPause()メソッドで行う必要があります.