2011年8月26日金曜日

finish()が実行されるタイミング

finish()が実行されるタイミング

finish()が実行されるタイミングについてはadsaria moodfinish()ではプロセスは終わらないに書かれているとおりです。
私なりに、私自身が納得できるように、実験用プログラムを作りました。


public class FinishTestActivity extends Activity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        
        ToneGenerator tg;
        tg = new ToneGenerator(AudioManager.STREAM_ALARM, 100);
        tg.startTone(ToneGenerator.TONE_DTMF_1);
        Log.d("FinishTest", "before finish()");
        finish();
        Log.d("FinishTest", "after finish()");
        tg.stopTone();
    }


    @Override
    protected void onDestroy() {
        Log.d("FinishTest", "onDestroy()");
        super.onDestroy();
    }
}

もし、finish()により、いきなりプログラムが終了するのであれば、tg.stopTone()が実行されないことになりますので、ビープ音が鳴り続けます。
しかし、ビープ音は鳴り止みますので、tg.stopTone()は実行されたということです。
ログには次のとおり記録されます。

08-26 11:35:18.325: DEBUG/FinishTest(785): before finish()
08-26 11:35:18.365: DEBUG/FinishTest(785): after finish()
08-26 11:35:19.635: DEBUG/FinishTest(785): onDestroy()

私なりの言葉で説明すると次のとおりになります。
命令の発出の仕方にはsend方式とpost方式があります。
send方式は命令を発出したら、即座にそれを実行する方式です。
post方式は命令を「メッセージ格納器」に入れるだけです。命令を受け取る側は暇になった時に「メッセージ格納器」から命令を取り出して実行するのです。
上記プログラムの例だと、onCreateメソッドの実行が完了した後が、暇になる時です。
finish()はpost方式なのです。


finish()を実行してもプロセスが生きていることは、DDMSやデバッガを使っていれば分かることなので、(内心、変だなと思いつつも)当たり前のようにも感じていました。

finish()ではプロセスは終わらないの記事で重要なのは、次の指摘です。
finish()を呼び出しても、アクティビティはDestroyはされるものの、プロセスとして残っていて(つまりメモリ上にクラスがロードされた状態で残っていて)、次回、再利用する時にはスタティックなメンバ変数の初期化は行ってくれない。
このことから、次の結論が出てきます。
アクティビティ開始時に値が定まっていなければならないメンバ変数の初期化は、宣言時ではなく、onCreate、もしくは必要の応じて、onStart、onResumeで実行する必要がある。
この場合、気になるのが、「次回、再利用する時」です。
onDestroy()した後で、利用者が同一のアプリの起動ボタンを押し下げた時が含まれるのであれば、この事実を周知しなければなりません。実際に役に立つプログラマは少数ですけど。

この続きをstatic変数の値は次回起動へ継承されるに書きました。

0 件のコメント:

コメントを投稿