素人プログラマ奮闘記

javaの初心者がAndroidのことを独学で勉強しつつ、メモを残していきます。

Activityライフサイクル

ライフサイクルをきっちり理解したうえでアプリ開発をしていかないと
とんでもないソフトが出来上がるため、注意が必要です。
色々Andoroidをいじってきましたが、いまだにライフサイクルについての知識が乏しかったので
一度まとめてみた。

アクティビティが開始(アンドロイドアプリ起動)されて(アンドロイドアプリ終了)破棄されるまでを
アクティビティのライフサイクルと呼ぶ。
ライフサイクルの間は、アクティビティは色々な状態を遷移し、対応する関数が呼ばれる。

ライフサイクル関係のメソッド一覧

onCreate()
アクティビティが初めて作成されるときに呼び出されます。

onStart()
アクティビティがユーザーから見えるようになる直前に呼び出されます。

onResume()
アクティビティがユーザーとの対話を開始する直前に呼び出されます。

onRestart()
アクティビティが停止した後、それをもう一度開始する直前に呼び出されます。

onPause()
システムが別のアクティビティを開始しようとしているときに呼び出されます。

onStop()
アクティビティがユーザーから見えなくなったときに呼び出されます。

onDestroy()
アクティビティが破棄される前に呼び出されます。


メソッドが呼ばれたときのログをとり
いくつかの画面遷移のパターンを操作したときに呼ばれるメソッドとその順番を確認してみました。
全体のソースは下記の通りです

package com.example.activitytest;

import android.os.Bundle;
import android.app.Activity;
import android.util.Log;
import android.view.Menu;

public class MainActivity extends Activity {

	private final String TAG = "MainActivity";
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);		
		Log.d(TAG,"onCreate");
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		// Inflate the menu; this adds items to the action bar if it is present.
		getMenuInflater().inflate(R.menu.main, menu);
		Log.d(TAG,"onCreateOptionsMenu");
		return true;
	}

	@Override
	protected void onDestroy() {
		// TODO 自動生成されたメソッド・スタブ
		super.onDestroy();
		Log.d(TAG,"onDestroy");
	}

	@Override
	protected void onPause() {
		// TODO 自動生成されたメソッド・スタブ
		super.onPause();
		Log.d(TAG,"onPause");
	}

	@Override
	protected void onRestart() {
		// TODO 自動生成されたメソッド・スタブ
		super.onRestart();
		Log.d(TAG,"onRestart");
	}

	@Override
	protected void onResume() {
		// TODO 自動生成されたメソッド・スタブ
		super.onResume();
		Log.d(TAG,"onResume");
	}

	@Override
	protected void onStart() {
		// TODO 自動生成されたメソッド・スタブ
		super.onStart();
		Log.d(TAG,"onStart");
	}

	@Override
	protected void onStop() {
		// TODO 自動生成されたメソッド・スタブ
		super.onStop();
		Log.d(TAG,"onStop");
	}
}

●アプリ起動時

10:36:29.435: D/MainActivity: onCreate
10:36:29.435: D/MainActivity: onStart
10:36:29.440: D/MainActivity: onResume
10:36:29.650: D/MainActivity: onCreateOptionsMenu
アプリのメイン画面が表示される。

●アプリ起動後、端末のバックボタン押下時

10:45:56.015: D/MainActivity: onPause
10:45:56.645: D/MainActivity: onStop
10:45:56.645: D/MainActivity: onDestroy
端末トップ画面が表示される。

●アプリ起動後、端末のホームボタン押下時

10:48:01.060: D/MainActivity: onPause
10:48:01.735: D/MainActivity: onStop

端末トップ画面が表示される。ここからまたアプリのアイコンをクリックすると・・・

10:49:04.085: D/MainActivity: onRestart
10:49:04.085: D/MainActivity: onStart
10:49:04.085: D/MainActivity: onResume
画面はメイン画面が表示される。

●アプリ起動中、着信した時

10:48:01.060: D/MainActivity: onPause
10:48:01.735: D/MainActivity: onStop
着信画面が表示される。

●アプリ起動後、アプリの終了ボタン押下(finish())

11:28:40.845: D/MainActivity: onPause
11:28:41.540: D/MainActivity: onStop
11:28:41.540: D/MainActivity: onDestroy
端末トップ画面が表示される。

●アプリ起動中、端末がスリープ状態になる

11:29:53.845: D/MainActivity: onPause
11:29:54.540: D/MainActivity: onStop

画面の電源がOFFになる。ここから再開すると・・・

11:31:04.085: D/MainActivity: onRestart
11:31:04.085: D/MainActivity: onStart
11:31:04.085: D/MainActivity: onResume

●アプリ起動に画面の向きを変える(縦向きから横向き)

11:38:59.410: D/MainActivity: onPause
11:38:59.410: D/MainActivity: onStop
11:38:59.410: D/MainActivity: onDestroy
11:38:59.570: D/MainActivity: onCreate
11:38:59.570: D/MainActivity: onStart
11:38:59.570: D/MainActivity: onCreateOptionsMenu
11:38:59.570: D/MainActivity: onResume

向きが変わった画面が表示される。さらに向きを元に戻すと。

11:44:38.890: D/MainActivity: onPause
11:44:38.890: D/MainActivity: onStop
11:44:38.890: D/MainActivity: onDestroy
11:44:39.120: D/MainActivity: onCreate
11:44:39.125: D/MainActivity: onStart
11:44:39.140: D/MainActivity: onCreateOptionsMenu
11:44:39.150: D/MainActivity: onResume

向きを変えるとonDestroyまでよんでるんですね・・・
これはしりませんでした(;´Д`)



カテゴリーへ

画面遷移時ライフサイクル

前回はアプリに画面が1つしかないパターンで検証しましたが
今回は複数画面が存在し、それぞれ画面遷移した際にどうなるかを見ていきたいと思います。

画面構成は以下のようにします。

メイン画面にはSub01に移動するボタンとアプリ終了ボタン。
Sub01画面にはメイン画面に移動するボタンSub02画面に移動するボタン。
Sub02画面にはSub01画面に移動するボタン。

以降にソース全体を記述します

●MainActivity.java

				
package com.example.activitytest;

import android.os.Bundle;
import android.app.Activity;
import android.content.Intent;
import android.util.Log;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;

public class MainActivity extends Activity implements OnClickListener{

	private final String TAG = "MainActivity";
	
	private Button sub01OpenButton = null;	//sub01画面表示ボタン
	private Button appEndButton = null;		//アプリ終了ボタン
	
	
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);		
		Log.d(TAG,"onCreate");
		
		//アプリ終了ボタン初期化
		this.appEndButton = (Button)findViewById(R.id.app_end_button);
		this.appEndButton.setOnClickListener(this);
		
		//サブ画面表示ボタン初期化
		this.sub01OpenButton = (Button)findViewById(R.id.sub01_open_button);
		this.sub01OpenButton.setOnClickListener(this);
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		// Inflate the menu; this adds items to the action bar if it is present.
		getMenuInflater().inflate(R.menu.main, menu);
		Log.d(TAG,"onCreateOptionsMenu");
		return true;
	}

	@Override
	protected void onDestroy() {
		// TODO 自動生成されたメソッド・スタブ
		super.onDestroy();
		Log.d(TAG,"onDestroy");
	}

	@Override
	protected void onPause() {
		// TODO 自動生成されたメソッド・スタブ
		super.onPause();
		Log.d(TAG,"onPause");
	}

	@Override
	protected void onRestart() {
		// TODO 自動生成されたメソッド・スタブ
		super.onRestart();
		Log.d(TAG,"onRestart");
	}

	@Override
	protected void onResume() {
		// TODO 自動生成されたメソッド・スタブ
		super.onResume();
		Log.d(TAG,"onResume");
	}

	@Override
	protected void onStart() {
		// TODO 自動生成されたメソッド・スタブ
		super.onStart();
		Log.d(TAG,"onStart");
	}

	@Override
	protected void onStop() {
		// TODO 自動生成されたメソッド・スタブ
		super.onStop();
		Log.d(TAG,"onStop");
	}

	@Override
	public void onClick(View v) {
		// TODO 自動生成されたメソッド・スタブ
		
		switch(v.getId()) {		
		case R.id.app_end_button:
			//終了ボタンが押された
			//画面終了
			this.finish();
			break;		
		case R.id.sub01_open_button:
			//Sub01へボタンが押された
			//Intentオブジェクト生成
			Intent intent = new Intent(this,Sub01Activity.class);
			//画面呼び出し
            startActivity(intent);
			break;		
		}
		
	}
}

●Sub01Activity.java
				
package com.example.activitytest;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;

public class Sub01Activity extends Activity implements OnClickListener{

	private final String TAG = "Sub01Activity";
	
	private Button sub02OpenButton = null;	//sub02画面表示ボタン
	private Button menuOpenButton = null;	//メニュに戻るボタン

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.sub01);		
		Log.d(TAG,"onCreate");
				
		this.sub02OpenButton = (Button)findViewById(R.id.sub02_open_button);
		this.sub02OpenButton.setOnClickListener(this);

		this.menuOpenButton = (Button)findViewById(R.id.main_open_button);
		this.menuOpenButton.setOnClickListener(this);
}

	@Override
	protected void onDestroy() {
		// TODO 自動生成されたメソッド・スタブ
		super.onDestroy();
		Log.d(TAG,"onDestroy");
	}

	@Override
	protected void onPause() {
		// TODO 自動生成されたメソッド・スタブ
		super.onPause();
		Log.d(TAG,"onPause");
	}

	@Override
	protected void onRestart() {
		// TODO 自動生成されたメソッド・スタブ
		super.onRestart();
		Log.d(TAG,"onRestart");
	}

	@Override
	protected void onResume() {
		// TODO 自動生成されたメソッド・スタブ
		super.onResume();
		Log.d(TAG,"onResume");
	}

	@Override
	protected void onStart() {
		// TODO 自動生成されたメソッド・スタブ
		super.onStart();
		Log.d(TAG,"onStart");
	}

	@Override
	protected void onStop() {
		// TODO 自動生成されたメソッド・スタブ
		super.onStop();
		Log.d(TAG,"onStop");
	}
	@Override
	public void onClick(View v) {
		// TODO 自動生成されたメソッド・スタブ
		switch(v.getId()) {		
		case R.id.sub02_open_button:
			//sub02へボタン押下	
			//Intentオブジェクト生成
			Intent intent = new Intent(this,Sub02Activity.class);
			//画面呼び出し
			startActivity(intent);
			//自画面終了
			this.finish();
			
			break;
		case R.id.main_open_button:
			//メニューボタン押下
			//自画面終了
			this.finish();
			break;		
		}

	}

}

●Sub02Activity.java
				
package com.example.activitytest;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;

public class Sub02Activity extends Activity implements OnClickListener{
	private final String TAG = "Sub02Activity";

	private Button sub01OpenButton = null;	//sub01画面表示ボタン

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.sub02);		
		Log.d(TAG,"onCreate");
		
		this.sub01OpenButton = (Button)findViewById(R.id.sub01_open_button);
		this.sub01OpenButton.setOnClickListener(this);

	}

	@Override
	protected void onDestroy() {
		// TODO 自動生成されたメソッド・スタブ
		super.onDestroy();
		Log.d(TAG,"onDestroy");
	}

	@Override
	protected void onPause() {
		// TODO 自動生成されたメソッド・スタブ
		super.onPause();
		Log.d(TAG,"onPause");
	}

	@Override
	protected void onRestart() {
		// TODO 自動生成されたメソッド・スタブ
		super.onRestart();
		Log.d(TAG,"onRestart");
	}

	@Override
	protected void onResume() {
		// TODO 自動生成されたメソッド・スタブ
		super.onResume();
		Log.d(TAG,"onResume");
	}

	@Override
	protected void onStart() {
		// TODO 自動生成されたメソッド・スタブ
		super.onStart();
		Log.d(TAG,"onStart");
	}

	@Override
	protected void onStop() {
		// TODO 自動生成されたメソッド・スタブ
		super.onStop();
		Log.d(TAG,"onStop");
	}
	@Override
	public void onClick(View v) {
		// TODO 自動生成されたメソッド・スタブ
		switch(v.getId()) {		
		case R.id.sub01_open_button:
			//sub01へボタン押下
			//Intentオブジェクト生成
			Intent intent = new Intent(this,Sub01Activity.class);
			//画面呼び出し
			startActivity(intent);
			this.finish();
			break;
		}
	}
}

●main.xml
				
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">
	<LinearLayout 
    	android:layout_width="match_parent"
       	android:layout_height="wrap_content"
       	android:orientation="horizontal">       
	    <TextView
	        android:layout_width="wrap_content"
	        android:layout_height="wrap_content"
        	android:text="Main"/>
	</LinearLayout>
	<LinearLayout
	    android:layout_width="match_parent"
	    android:layout_height="wrap_content"
	    android:orientation="horizontal" >
	    <Button
	        android:id="@+id/sub01_open_button"
	        android:layout_width="wrap_content"
	        android:layout_height="wrap_content"
	        android:text="Sub01へ" />
	    <Button
	        android:id="@+id/app_end_button"
	        android:layout_width="wrap_content"
	        android:layout_height="wrap_content"
	        android:text="終了" />
	</LinearLayout>    
</LinearLayout>

●sub01.xml
				
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">
	<LinearLayout 
    	android:layout_width="match_parent"
       	android:layout_height="wrap_content"
       	android:orientation="horizontal">       
	    <TextView
	        android:layout_width="wrap_content"
	        android:layout_height="wrap_content"
        	android:text="sub01"/>
	</LinearLayout>
	<LinearLayout
	    android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">
	    <Button 
	        android:id="@+id/main_open_button"
        	android:layout_width="wrap_content"
        	android:layout_height="wrap_content"
        	android:text="mainへ"/>
	    <Button
	        android:id="@+id/sub02_open_button"
	        android:layout_width="wrap_content"
        	android:layout_height="wrap_content"
        	android:text="Sub02へ"/>
	</LinearLayout>    
</LinearLayout>

●sub02.xml
				
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">
	<LinearLayout 
    	android:layout_width="match_parent"
       	android:layout_height="wrap_content"
       	android:orientation="horizontal">       
	    <TextView
	        android:layout_width="wrap_content"
	        android:layout_height="wrap_content"
        	android:text="sub02"/>
	</LinearLayout>
	<LinearLayout
	    android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">
	    <Button
	        android:id="@+id/sub01_open_button"
	        android:layout_width="wrap_content"
        	android:layout_height="wrap_content"
        	android:text="Sub03へ"/>
	</LinearLayout>    
</LinearLayout>

ではそれぞれの動作したときのサイクルを見ていきます。

●アプリ起動時

19:29:40.125: D/MainActivity: onCreate
19:29:40.130: D/MainActivity: onStart
19:29:40.130: D/MainActivity: onResume
19:29:40.275: D/MainActivity: onCreateOptionsMenu
アプリのメイン画面が表示される。

●Main画面よりSub01へボタン押下時

19:30:27.380: D/MainActivity: onPause
19:30:27.475: D/Sub01Activity: onCreate
19:30:27.475: D/Sub01Activity: onStart
19:30:27.475: D/Sub01Activity: onResume
19:30:27.810: D/MainActivity: onStop
Sub01が表示される
MainActivityはonStopになり後ろに積まれている状態

●Sub01画面よりSub02へボタン押下時

19:44:08.490: D/Sub01Activity: onPause
19:44:08.570: D/Sub02Activity: onCreate
19:44:08.575: D/Sub02Activity: onStart
19:44:08.575: D/Sub02Activity: onResume
19:44:08.870: D/Sub01Activity: onStop
19:44:08.870: D/Sub01Activity: onDestroy
Sub02が表示される

●Sub02画面よりSub01へボタン押下時

19:45:55.680: D/Sub02Activity: onPause
19:45:55.795: D/Sub01Activity: onCreate
19:45:55.795: D/Sub01Activity: onStart
19:45:55.795: D/Sub01Activity: onResume
19:45:56.105: D/Sub02Activity: onStop
19:45:56.105: D/Sub02Activity: onDestroy
Sub01が表示される

●Sub01画面よりMainへボタン押下時

19:46:33.815: D/Sub01Activity: onPause
19:46:33.840: D/MainActivity: onRestart
19:46:33.840: D/MainActivity: onStart
19:46:33.840: D/MainActivity: onResume
19:46:34.110: D/Sub01Activity: onStop
19:46:34.110: D/Sub01Activity: onDestroy
アプリのメイン画面が表示される。

●Main画面より終了ボタン押下時

19:47:34.035: D/MainActivity: onPause
19:47:34.705: D/MainActivity: onStop
19:47:34.705: D/MainActivity: onDestroy

●Sub01画面で端末のバックボタン押下時

19:50:15.410: D/Sub01Activity: onPause
19:50:15.420: D/MainActivity: onRestart
19:50:15.420: D/MainActivity: onStart
19:50:15.420: D/MainActivity: onResume
19:50:15.700: D/Sub01Activity: onStop
19:50:15.700: D/Sub01Activity: onDestroy
アプリのメイン画面が表示される。
Mainへボタン押下時と同じ動きですね~(∩´∀`)∩

●Sub01画面で端末のホームボタン押下時

19:51:54.520: D/Sub01Activity: onPause
19:51:55.150: D/Sub01Activity: onStop
端末のトップ画面が表示される。
からの~再開時
19:52:23.055: D/Sub01Activity: onRestart
19:52:23.055: D/Sub01Activity: onStart
19:52:23.055: D/Sub01Activity: onResume
Sub01が表示される

●検証結果
状態遷移する際にMein画面以外はFinish();を呼んでいるが、
Main画面以外での端末ボタン操作は、Sub画面のライフサイクル遷移となり、メイン画面のライフサイクル遷移は変わらない。
ちなみに画面遷移時にFinish();を呼ばずに状態遷移すると、表示した画面が終了せずに積み重なっておかしな動作になるので注意しましょう。

Main画面以外の画面を表示中は常にメイン画面が積まれている状態にするのが普通らしいです。


カテゴリーへ

inserted by FC2 system