본문 바로가기

프로그래밍/Android

Android 기본 프로젝트 MainActivity.java 분석



package com.example.sample;

import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v7.app.ActionBarActivity;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.TextView;
import android.widget.Toast;

public class MainActivity extends ActionBarActivity {

	
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);

		/*
		 * 초기 액티비티가 화면에 보여질때 setContentView 메서드를 통해 화면에 View 를 붙여준다.
		 * res/layout/activity_main.xml 을 액티비티의 레이아웃으로 설정한다.
		 * 하지만 activity_main.xml 안에서는 FrameLayout 하나만 선언 되어 있는데, 이는 해당 레이아웃에
		 * 프레그먼트를 사용하기 위해 미리 선언 되어 있다.
		 */

		setContentView(R.layout.activity_main);

		/*
		 * savedInstanceState 란 무엇인가 ?
		 * 
		 * savedInstanceState 객체는 onSaveInstanceState 메서드에서 저장한 Bundle 객체에 대한 정보를 가지고 있음
		 * onSaveInstanceState 메서드를 구현하기 위해선 Override 해야 한다.
		 * onSaveInstanceState 메서드가 호출되는 시점은 메모리 부족/강제종료 및 스크린 Orientation 이 변경될때 호출된다.
		 */
		
		if (savedInstanceState == null) { //초기 프로젝트 실행후 액티비티의 상태 저장값은 NULL

			//ID 이름이 container(Frame Layout)인 레이아웃 안에  프래그먼트를 붙이기 위해 아래 코드 사용
			getSupportFragmentManager().beginTransaction()
					.add(R.id.container, new PlaceholderFragment()).commit();
			
		}
	}

	//액션바에 옵션메뉴를 달기 위해선 onCreateOptionsMenu 를 구현해야 한다.
	@Override
	public boolean onCreateOptionsMenu(Menu menu) {

		/*
		 * res/menu/menu.xml 에 메뉴를 구성할수 있다.
		 * 이곳에선 구성된 메뉴를 생성한다.
		 * 초기 프로젝트 생성시 Settings 이라는 기본 메뉴가 들어가 있다.
		 */

		getMenuInflater().inflate(R.menu.main, menu);
		return true;
	}

	//옵션메뉴 클릭시 onOptionsItemSelected 메서드가 호출되며, 해당 메서드에서 작동하는 코드를 구현한다.
	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
		
		//각 옵션메뉴 버튼마다 고유의 ID 를 가지고 있으므로, ID 를 통해 어떤 메뉴를 클릭하였는지 구분한다.
		int id = item.getItemId();
		if (id == R.id.action_settings) {
			return true;
		}
		return super.onOptionsItemSelected(item);
	}
	
	//PlaceholderFragment 클래스를 정적 내부 클래스(Static Nested Class) 로 선언하여, 외부에서도 접근할수 있도록 선언한다.
	public static class PlaceholderFragment extends Fragment {

		//생성자
		public PlaceholderFragment() {
			
		}

		//프레그먼트가 화면에 보여질 View 를 구성한다.
		@Override
		public View onCreateView(LayoutInflater inflater, ViewGroup container,
				Bundle savedInstanceState) {
			/*
			 * LayoutInflater 를 사용하여 해당 프레그먼트의 레이아웃을 설정하고 xml 을 View 객체로 생성한다.
			 * 실질적으로 컴파일 될때 보여질 화면은 fragment_main 에서 담당한다.
			 */
			View rootView = inflater.inflate(R.layout.fragment_main, container, false);
			
			/*
			 * fragment_main.xml 에 선언되어 있는 TextView (Hello World) 를 코드상에서 객체로 사용하기 위해서는 해당 주소를 찾아 TextView 로 캐스팅 해야 한다.
			 * 일반적으로 액티비티 안에서 View 에 대한 ID 값을 참조하기 위해서 findViewById 를 사용하였지만,
			 * Fragment는 객체로 생성한 View 를 통해 View(컴포넌트)의 ID 값을 찾아야 한다. (아래 코드 참조)
			 */
			TextView textView = (TextView)rootView.findViewById(R.id.textView); //rootView 객체에서 findViewById 메서드 사용하여 View의 ID 를 통해 TextView 로 캐스팅 한다. 
			textView.setOnClickListener(new OnClickListener() {
				
				@Override
				public void onClick(View v) {
					Toast.makeText(getActivity(), "Hello World 클릭!", Toast.LENGTH_SHORT).show();
				}
				
			});
			return rootView;
		}
	}

}

 

※ 프레그먼트(PlaceholderFragment Class)를 왜 정적 내부 클래스 (Static Nested Class) 로 선언 하였는가?

 

자바 기초가 탄탄하신분들은 이미 눈치 채셨을겁니다.
(이너클래스, 익명 이너클래스, 내부 클래스, 로컬 클래스 에 대해 잘 모른다면 자바 기본 서적을 참고하세요)

 

다른 클래스에서 특정 외부 클래스(Outer Class) 안에 있는 내부 클래스(Inner Class) 를 접근하기 위해서는,

반드시 Outer Class 를 통해서 (객체 생성) Inner Class 에 접근이 가능합니다.

하지만 정적 이너 클래스의 경우 Outer Class의 객체 생성 없이도 객체 생성이 가능합니다.

 

 

즉, PlaceholderFragment Class 를 만약 이너 클래스로 선언 하였다면,

(ex. public class PlaceholderFragment)

다른 클래스 에선 해당 클래스로 접근할수 있는 방법은 아래와 같습니다.

 

package com.example.sample;


public class A {
	
	public void Test() {
		
		//Outer Class 를 먼저 생성후 Inner Class 를 생성할수 있다.
		//즉 MainActivity 안에 PlaceholderFragment 클래스가 존재하기 때문에 아래 작업을 해야한다.

		MainActivity outer = new MainActivity();
		MainActivity.PlaceholderFragment inner = outer.new PlaceholderFragment();
	}
}

(MainActivity 안에서는 PlaceholderFragment a = new PlaceholderFragment(); 와 같이 선언 가능)

 

반대로 PlaceholderFragment Class 를 만약 정적 이너 클래스로 선언 하였다면,

(ex. public static class PlaceholderFragment)

다른 클래스 에선 해당 클래스로 접근할수 있는 방법은 아래와 같습니다.

 

package com.example.sample; public class A { public void Test() { //정적 이너 클래스 인경우 아래 한줄로 객체 생성이 가능하다. //즉 MainActivity 안에 PlaceholderFragment 정적 이너 클래스가 존재하기 때문에 아래 작업을 해야한다. MainActivity.PlaceholderFragment fragment = new MainActivity.PlaceholderFragment(); } }