본문 바로가기

어플리케이션 구성/액티비티(Activity)

액티비티 생애주기, 눈으로 확인하자!

강좌 작성환경
SDK Version : Android SDK 1.6, release 1
ADT Version : 0.9.3

추후 SDK업데이트로 인해 글의 내용과 실제 내용간 차이가 있을 수 있습니다.

지난 글 (2009/09/18 - [어플리케이션 구성/액티비티(Activity)] - 액티비티의 생애주기(Lifecycle)  에서 액티비티의 생애주기에 대해 알아보았습니다. 글에서 최대한 쉽게 설명한다고 설명하긴 했는데, 아무래도 실제로 동작하는 과정을 확인해보는 것이 더 이해가 빠르겠지요?

이번 글에서는 실제로 액티비티 라이프사이클을 확인할 수 있도록 상태가 변할 때마다 호출되는 메소드 안에 디버그 메시지를 출력하는 코드를 삽입하여 LogCat을 통해 상태변화를 관찰할 수 있도록 해보겠습니다.

새 프로젝트를 생성합니다. 저는 ActivityLifeCycle라는 이름으로 프로젝트를 생성하고, 액티비티 이름은 LifeCycleTester로 지정하였습니다. 액티비티 생애주기를 위한 어플리케이션은 크게 메인 액티비티에서 다른 액티비티를 호출하고, 호출한 액티비티를 종료하는 것과 다이얼로그를 띄우는 것으로 이루어져 있습니다. 즉, 액티비티는 두 개를 생성해야겠지요?

액티비티를 생성하는 과정을 잘 모르시는 분은 이 포스트를 참고하세요.

아래와 같이 코드를 작성합니다.

[LifeCycleTester.java]

package com.androidhuman.ActivityLifeCycle;

import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
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 LifeCycleTester extends Activity {
	private static final String TAG = "LifeCycleTester";
	
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.i(TAG, "onCreate()");
        setContentView(R.layout.main);
        Button launchButton = (Button)findViewById(R.id.launchbutton);
        Button showdialog = (Button)findViewById(R.id.showdialog);
        launchButton.setOnClickListener(new OnClickListener(){

			public void onClick(View arg0) {
				startActivity(new Intent(LifeCycleTester.this, SubActivity.class));
				
			}
        	
        });
        
        showdialog.setOnClickListener(new OnClickListener(){

			public void onClick(View v) {
				AlertDialog.Builder dialog = 
					new AlertDialog.Builder(LifeCycleTester.this);
				dialog.setMessage("Dialog!");
				dialog.setTitle("Dialog Title");
				dialog.setPositiveButton("OK", 
						new DialogInterface.OnClickListener() {
					
					public void onClick(DialogInterface dialog, int which) {
						// TODO Auto-generated method stub
						
					}
				});
				dialog.show();
				
			}
        	
        });
    }
    
    @Override
    public void onPause(){
    	super.onPause();
    	Log.i(TAG, "onPause()");
    }
    
    @Override
    public void onStop(){
    	super.onStop();
    	Log.i(TAG, "onStop()");
    }
    
    @Override
    public void onResume(){
    	super.onResume();
    	Log.i(TAG, "onResume()");
    }
    
    @Override
    public void onStart(){
    	super.onStart();
    	Log.i(TAG, "onStart()");
    }
    
    @Override
    public void onRestart(){
    	super.onRestart();
    	Log.i(TAG, "onRestart()");
    }
    
    @Override
    public void onDestroy(){
    	super.onDestroy();
    	Log.i(TAG, "onDestroy()");
    }
}

위의 코드에서 확인할 수 있듯이, 액티비티의 상태가 변할 때마다 호출되는 메소드들을 오버라이드 한 후, 그곳에 LogCat을 통해 메시지를 확인할 수 있게끔 코드를 추가하였습니다.


Button launchButton = (Button)findViewById(R.id.launchbutton);
        Button showdialog = (Button)findViewById(R.id.showdialog);
        launchButton.setOnClickListener(new OnClickListener(){

			public void onClick(View arg0) {
				startActivity(new Intent(LifeCycleTester.this, SubActivity.class));
				
			}
        	
        });
        
        showdialog.setOnClickListener(new OnClickListener(){

			public void onClick(View v) {
				AlertDialog.Builder dialog = 
					new AlertDialog.Builder(LifeCycleTester.this);
				dialog.setMessage("Dialog!");
				dialog.setTitle("Dialog Title");
				dialog.setPositiveButton("OK", 
						new DialogInterface.OnClickListener() {
					
					public void onClick(DialogInterface dialog, int which) {
						// TODO Auto-generated method stub
						
					}
				});
				dialog.show();
				
			}
        	
        });


첫 번째 액티비티의 버튼은 두개로, 첫번째 버튼은 다른 액티비티를 띄우도록, 두번째 버튼은 다이얼로그를 띄우도록 되어있는 것을 확인할 수 있습니다.



[SubActivity.java]

package com.androidhuman.ActivityLifeCycle;

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

public class SubActivity extends Activity {
	
	private static final String TAG = "SubActivity";

	/** Called when the activity is first created. */
	@Override
	public void onCreate(Bundle savedInstanceState) {
	    super.onCreate(savedInstanceState);
	    Log.i(TAG, "onCreate()");
	    setContentView(R.layout.sub);

	    Button destroyButton = (Button)findViewById(R.id.destroybutton);
	    destroyButton.setOnClickListener(new OnClickListener(){

			public void onClick(View v) {
				finish();
				
			}
	    	
	    });
	}
	
	@Override
    public void onPause(){
    	super.onPause();
    	Log.i(TAG, "onPause()");
    }
    
    @Override
    public void onStop(){
    	super.onStop();
    	Log.i(TAG, "onStop()");
    }
    
    @Override
    public void onResume(){
    	super.onResume();
    	Log.i(TAG, "onResume()");
    }
    
    @Override
    public void onStart(){
    	super.onStart();
    	Log.i(TAG, "onStart()");
    }
    
    @Override
    public void onRestart(){
    	super.onRestart();
    	Log.i(TAG, "onRestart()");
    }
    
    @Override
    public void onDestroy(){
    	super.onDestroy();
    	Log.i(TAG, "onDestroy()");
    }

}

두 번쨰 액티비티의 코드입니다. 버튼을 누르면 액티비티가 종료되게 되어있습니다.

아래는 각 액티비티의 레이아웃입니다.


[main.xml - LifeCycleTester]

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    >
<TextView  
    android:layout_width="fill_parent" 
    android:layout_height="wrap_content" 
    android:text="Main Activity" 
    />
<Button android:layout_width="wrap_content"
  android:layout_height="wrap_content" 
  android:id="@+id/launchbutton" 
  android:text="Launch Sub-Activity"></Button>

<Button android:layout_width="wrap_content" 
  android:layout_height="wrap_content" 
  android:id="@+id/showdialog" 
  android:text="Show Dialog"></Button>
</LinearLayout>



[sub.xml - SubActivity]

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="wrap_content"
  android:layout_height="wrap_content" android:orientation="vertical">
  
<TextView android:layout_width="wrap_content" 
 android:layout_height="wrap_content" 
 android:text="Sub-activity"></TextView> 

<Button android:layout_height="wrap_content"
 android:layout_width="wrap_content"
 android:id="@+id/destroybutton" 
 android:text="Destroy this activity"></Button>
</LinearLayout>



위와 같이 작성을 완료하였다면, 이제 테스트를 해 볼 차례입니다. 프로젝트를 실행하여 에뮬레이터에 설치하도록 합시다. 보통 실행 버튼을 눌러 프로젝트를 실행하면 어플리케이션이 자동으로 실행되게 됩니다. 우선은 테스트를 위해 홈 버튼을 눌러 메인 화면으로 빠져나온 후, 프로세스를 종료시킵니다.

이클립스의 DDMS 화면 좌측 상단을 보면 컴퓨터와 연결된 에뮬레이터/장치의 목록과 각 장치에서 실행되고 있는 프로세스의 목록이 표시되는데, 이 중에서 종료시킬 프로세스를 선택한 후 빨간색 STOP 버튼을 누르면 프로세스를 강제로 종료할 수 있습니다.

종료할 프로세스를 선택한 후, Stop Process 버튼을 눌러준다.

 

프로세스를 종료한 후, 다시 ActivityLifeCycle 어플리케이션을 실행시키기 전에 미리 DDMS 화면의 하단에 위치한 LogCat 창을 클릭해서 내용을 확인할 수 있게 해 놓은 후, 어플리케이션을 다시 실행시켜줍니다.

어플리케이션을 실행시키면, 다음과 같이 액티비티의 상태 변화에 따라 로그가 출력되는 것을 볼 수 있습니다. 이 로그를 보면서 액티비티의 상태가 어떻게 변화하는지 알 수 있죠.


1. 어플리케이션 최초 실행


LifeCycleTester 어플리케이션이 실행된 모습입니다. 첫 액티비티가 화면에 표시되었습니다. LogCat을 확인해보니, 아래와 같이 액티비티의 상태가 어떻게 변했는지 표시되는군요. 우리가 알고있던 것처럼 onCreate() -  onStart() - onResume()순으로 상태가 변화하는 것을 관찰할 수 있습니다.



2. Dialog 호출

두번째 버튼을 눌러 다이얼로그를 호출해봅시다. 현재 액티비티가 가려질 때, 그 액티비티는 일시정지 상태가 되지만 다이얼로그는 그 액티비티의 일부로 보기 때문에 화면이 가려진다 할지라도 일시정지 상태로 변하지 않습니다.



3. 다른 액티비티 호출 / 종료

이번에는 첫번째 버튼을 눌러 다른 액티비티를 호출했다가, 종료해보도록 합니다. 버튼을 누르면 두번째 액티비티가 호출되며 첫번째 액티비티는 화면에서 사라지게 되고, 정지 상태(onStop())로 변하게 됩니다.


아래 로그를 보면, 두번째 액티비티인 SubActivity를 호출하면서 첫번째 액티비티가 정지 상태로 변하는 것을 관찰할 수 있습니다.



이후, 두번째 액티비티를 종료하는 버튼, "Destroy this Activity" 버튼을 누르면 두번째 액티비티가 종료되면서 다시 첫번째 액티비티가 화면에 나타나게 됩니다.


이렇게 해서 다시 첫 번째 액티비티가 표시된 후, Home버튼이나 Back 버튼을 눌러 첫번째 액티비티가 화면에서 사라진다 할지라도 첫번째 액티비티가 소멸(onDestroy()) 되지 않고 onStop() 상태로 대기하고 있는 것을 관찰할 수 있을 겁니다. 이렇게 액티비티는 특별히 메모리가 매우 부족한 경우가 아니면 바로 메모리에서 소멸되지 않고 메모리에 상주하여 다시 액티비티가 실행될 때 걸리는 시간을 줄여줍니다.


강좌에 사용했던 어플리케이션의 소스코드를 첨부합니다.