티스토리 툴바

블로그 이미지
그때의 이야기, 우리들의 소중한 꿈이 되었다. 밍공™

카테고리

분류 전체보기 (12)
소소한 일상 (0)
생각속으로.. (0)
읽은 책 (0)
세상 이야기 (0)
지름신 강림 (0)
페이퍼크래프트 (0)
정보 (0)
Android (11)
Total3,428
Today1
Yesterday1
Android] 한 줄에서 몇 줄로 되는 필요한 잡코드들 ㅋㅋ

17. Android 키보드 숫자형으로 시작하게 하기
edittext.setInputType(InputType.TYPE_CLASS_NUMBER);

16. Android listview 검정화면 없애기
android:cacheColorHint="#00000000"

15. Android 화면 고정하기

AndroidManifest.xml의 activity 속성중 screenOrientation을 다음과 같이 지정해준다.


//화면을 세로로 유지
android:label="@string/app_name"
android:screenOrientation="portrait">
//화면을 가로로 유지
android:label="@string/app_name"
android:screenOrientation="landscape">
자바 소스에서
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);

14. Android Handler example
// 시간주고 바로 뜨게 하기 20이 최소 가능 값..
new Handler().postDelayed(new Runnable() {
public void run() {
openOptionsMenu();
}
}, 20);

13. Android 소프트 키보드 끄기 및 보이기 및 숨기기
// 키보드 오프시키는 소스..
EditText et = (EditText)findViewById(R.id.menu6_e_number);
et.setInputType(0); //가상키보드 오프

1. 보이게 하기

EditText et = (EditText)findViewById(R.id.moneyEdit);
et.setInputType(0); //가상키보드 오프

et.setOnClickListener(new OnClickListener() {
public void onClick(View arg0) {
InputMethodManager imm = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE);
imm.showSoftInput(input, 0);
}
});

InputMethodManager imm = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE);
imm.showSoftInput(editText, 0);

2. 숨기기
InputMethodManager imm = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(myEditText.getWindowToken(), 0);


12. Android Edittext Hint, 흐리게 보이기
android:hint="ex) 안드로이드"


11. Android EditText 숫자키만 허용하기

DigitsKeyListener digit =
new DigitsKeyListener(true, true); // first true : is signed, second one : is decimal
digit.setKeyListener( MyDigitKeyListener );


위와같이 하거나 xml 에서

android:inputType="number"


10. Android Option menu 실행 소스
openOptionsMenu();


9. Android Menu 만들기
- xml 소스
res/menu/menu.menu


android:id="@+id/adjust"
android:title="수정"
android:orderInCategory="1" >

android:id="@+id/delete"
android:title="삭제"
android:orderInCategory="2" >



- 자바 소스
// OptionMenu
public boolean onCreateOptionsMenu(Menu menu){
getMenuInflater().inflate(R.menu.del_adjust, menu);
return true;
}

// OptionMenu click event
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.adjust:
finish();
return true;

case R.id.delete:
finish();
return true;
}
return false;
}

8. Android Dialog 만들기 (Android.Dialog.Builder())

기존에는 Activity에서 showAlert(()를 제공해줬나보다. (예제를 보니...)
더 이상 지원하지 않기 때문에 AlertDialog.Builder()를 이용하여 Dialog를 생성하였다.

*onClickLister() 생성시 반드시 DialogInterface.OnClickListener()라고 클래스를 적어줘야 한다.
(Activity에서 button 클릭 이벤트를 처리하기 위해 import한 View 클래스에 OnClickListener 메소드가 있다.)

a. Android yes or no - 버튼 2개짜리
new AlertDialog.Builder(LoginMainActivity.this)
.setTitle("Login Data")
.setMessage("rosa : test") //줄였음
.setPositiveButton("Yes", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
//...할일
}
})
.setNegativeButton("No", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
//...할일
}
})
.show();

b. Android ok (or cancel)
new AlertDialog.Builder(LoginMainActivity.this)
.setTitle("Login Data")
.setMessage("rosa : test") //줄였음
.setNeutralButton("OK", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
//...할일
}
})
.show();

c. Android 다른 layout 출력
new AlertDialog.Builder(LoginMainActivity.this)
.setTitle("list 예제")
.setItems(R.array.listBtnArray, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int selectedIndex) {
String[] list = getResources().getStringArray(R.array.listBtnArray);
new AlertDialog.Builder(LoginMainActivity.this)
.setTitle("선택한 리스트 아이템")
.setMessage(list[selectedIndex])
.setNeutralButton("OK", new DialogInterface.OnClickListener(){
@Override
public void onClick(DialogInterface dialog, int which) {
// TODO Auto-generated method stub
}
});
}
})
.show();

--
value 값으로 array 추가

One
Two
Three





7. Android 뒤로 가기 키
onBackPressed();

6. Android 바이브레이터
Vibrator vibe = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
vibe.vibrate(500);
// 퍼미션



5. Android 밝기 셋팅
Window w = getWindow();
WindowManager.LayoutParams lp = getWindow().getAttributes();
lp.screenBrightness = 0~1까지의 float 값;
w.setAttributes(lp);


-1.f를 주면 default 밝기로 세팅됩니다.

4. Android 화면 꺼지는것 막기
현재 Activity가 보여지고 있는 동안은 시간이 지나도
화면이 자동으로 꺼지지 않도록 합니다.
즉 단말이 슬립상태로 들어가지 않고 계속 화면을 켜놓습니다.

getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);

3. Android toast
1-Type
Toast.makeText.(this, "토스트 메세지", Toast.LENGTH_SHORT).show();

2-Type
Context context = getApplicationContext();
String msg = "";
int duration = Toast.LENGTH_SHORT;
Toast.makeText(context, b, duration).show();


2. Android View 백그라운드 색 변경
TextView a = null;
a.setBackgroundColor(Color.WHITE);

1. Android timer 이용
http://docs.androidside.com/docs/reference/java/util/TimerTask.html
--------------------------------------------------------------------------------------------------
모토로이 볼륨 올리고 내리는 버튼 키값을 알아내서
edittext 에 원하는 값을 넣는 방법 볼룸 위아래 버튼을 누르면
화면에 벨로시 볼륨 조절하는 창이 나타나는데 완전히 키값을 가로채는 방법

et_editText.setOnKeyListener(new OnKeyListener() {

@Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
// TODO Auto-generated method stub
if(event.getAction() == KeyEvent.ACTION_DOWN){
if(keyCode == 24 || keyCode == 25){
et_editText.setText("1234567890");

return true;
}
}
return false;
}

});


- 전체적으로 필요한 기능
// 종료 후 재 부팅시 기능이 죽지않고 유지되게 하는 방법들..
http://www.androidpub.com/android_dev_qna/189549

- 박사마 만드는데 필요한 기능
// view에서 페이지 넘기는 기능
API Demos에서 Animation에 간단하게 Fade in, Zoom in 효과가 있네요.

내가 만드는 부분에 필요한 부분들
// 강제로 클릭을 발생시키는 이벤트

dispatchTouchEvent
// 좌표관련들..
getWidth()랑 getHeight()로 전체 좌표값을 얻어오고 %로 비율 정해서 좌표값 설정하세요




출처 : Posted by Winchester.K

\\=> http://winchester.tistory.com/entry/Android-%ED%95%9C-%EC%A4%84%EC%97%90%EC%84%9C-%EB%AA%87-%EC%A4%84%EB%A1%9C-%EB%90%98%EB%8A%94-%ED%95%84%EC%9A%94%ED%95%9C-%EC%9E%A1%EC%BD%94%EB%93%9C%EB%93%A4-%E3%85%8B%E3%85%8B
저작자 표시
Posted by 훈남, 밍공™

댓글을 달아 주세요

TITLE : Android Custom ToastView

Date : 04/17/2010

Writen by Dayyoung

Description :

This is Source that make Custom ToastView by XML Inflator..

사용자 정의 ToastView 구현.

Download : customtoastview

일반적인 ToastView의 형태는 다음과 같다.

Toast.makeText(getApplicationContext(), “Hello!\nNomarl Test”, Toast.LENGTH_LONG).show();

명령으로 생성및 알림화면을 뛰우면서 debug/실시간에러 표시에도 활용된다.

1. 사용자정의 를 원하는 뷰의 배경을 그림판으로 제작합니다.

2. mytoast.xml 이라는 사용자정의 XML을 구성합니다. (레이아웃안에는 본인이 희망하는 뷰집합)

레이아웃과 텍스트의 ID 및 drawble에 그림판으로 제작한 이미지를 적용합니다.

3. 실시간으로 mytoast.xml파일을 인스턴스화 화며,

인스턴스화된 레이아웃을 역시 실시간으로 생성한 ToastView에 적용한다.

LayoutInflater inflater = getLayoutInflater();

//레이아웃을 뷰처럼 인스턴스화 시켜줄 인플래이터 호출

View layout = inflater.inflate(R.layout.mytoast,(ViewGroup)findViewById(R.id.my_toast_layout_root));

//레이아웃 생성

TextView text = (TextView)layout.findViewById(R.id.text);

text.setText(“경고! \n 안드로바이러스 침투!”);

//레이아웃에 소속된 textView 호출

Toast toast = new Toast(getApplicationContext());

//Toast 생성 인자값이 this가 아닌이유는 Toast생성을 액티비티가 아닌 버튼에서 하기 때문이다.

toast.setGravity(Gravity.CENTER, 0, 0);

toast.setDuration(3);

toast.setView(layout);

//Toast에 생성된 layout 적용

toast.show();

//토스트 화면 전환

<View를 Custom하기위한 일반사항>

1. View는 Layout이고 Layout은 View 이다.

말이 좀 이상한데. . 안드로이드 라이브러리에서는 두개를 동일한 요소로 보고있습니다.

Layout은 Android XML로 사용자가 위치를 조정하는 역할을 하는건데 . .머가 같은지 모르겠지만

즉, Layout을 쓸때도 View처럼 쓸 수 있다는 거라네요. 컴퍼지트 패턴이 적용됫다고 합니다..

컴포지트 패턴(Composite Pattern) : 컴포지트 패턴을 이용하면 객체들을 트리 구조로 구성하여 부분과 전체를 나타내는 계층구조로 만들 수 있습니다. 이 패턴을 이용하면 클라이언트에서 개별 객체와 다른 객체들로 구성된 복합 객체(Composite)를 똑같은 방법으로 다룰 수 있습니다.

2. 일반적으로 View를 사용자정의 할 때에는 아답터패턴이 쓰인다.

토스트뷰에서는 아답터패턴이 쓰이지 않은 단순한 경우이지만 대부분의 사용자정의 뷰를 만들때는 아답터패턴이 쓰임.

어댑터 패턴(Adapter Pattern) : 한 클래스의 인터페이스를 클라이언트에서 사용하고자 하는 다른 인터페이스로 변환합니다. 어댑터를 이용하면 인터페이스 호환성 문제 때문에 같이 쓸 수 없는 클래스들을 연결해서 쓸 수 있습니다.

[출처] 객체지향 디자인 패턴 – head first design pattern 요약|작성자 오사마
Creative Commons License
이 저작물은 크리에이티브 커먼즈 저작자표시 3.0 Unported 라이선스에 따라 이용할 수 있습니다.

저작자 표시
Posted by 훈남, 밍공™

댓글을 달아 주세요

custom TabView

Android / 2010/07/06 18:15

.xml

 

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

 <ImageView android:id="@+id/IVIcon"
  android:src="@drawable/icon"
  android:layout_width="wrap_content"
  android:layout_gravity="center"/>
 
 <TextView android:id="@+id/TVCaption"
  android:text="Caption"
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
  android:layout_gravity="center"/>
</LinearLayout>

 

 

.java

 

TabHost tabHost = (TabHost) findViewById(R.id.tabHost);

// TabHost를 findViewById로 생성한 후 Tab추가 전에 꼭 실행해 주어야 함.
tabHost.setup();

// 새로운 Tab을 생성하기 위한 Tab객체 생성
TabHost.TabSpec spec;

// Custom View for TabWidget
LayoutInFlater layout = getLayoutInglater();

// 첫번째 Tab 설정 및 등록
spec = tabHost.newTabSpec("Tab 00");
// 새 Tab생성
View vTab1 = layout.inflate(R.layout.mytabwidget, null);
TextView tvCaption = (TextView) vTab1.findViewById(R.id.TVCaption);
tvCaption.setText("Custom Tab 1");
spec.setIndicator(vTab1);

// Tab 제목
spec.setContent(R.id.layout);
// Tab 내용
tabHost.addTab(spec);

//생성 된 Tab등록
// 두번째 Tab 설정 및 등록

 

저작자 표시
Posted by 훈남, 밍공™

댓글을 달아 주세요

 - 안드로이드 액티비티 좀더 자세히 살펴보기

 * 애플리케이션을 위한 사용자 인터페이스 화면을 만들기 위해서는, Activity 클래스를 확장하고, 뷰를 사용해 사용자 상호작용을 제공한다

 * 액티비티 만들기 : 새로운 액티비티를 생성하려면, Activity 클래스를 확장한 다음 사용자 인터페이스를 정의하고 원하는 기능을 구현한다.

 * 액티비티 수명주기 : 활성Active(화면에 보이고 포커스를 가지며 사용자 입력을 받는다, 다른 액티비티가 활성화되면 기존의 활성 액티비티는 일시 중지될 것이다)

일시 중지Paused(투명한 액티비티나 화면 전체를 사용하지 않는 액티비티가 그 앞에 활성화되는 경우 도달된다),

중지Stopped(화면에 보이지 않을 경우 "중지"된다)

비활성Inactive(종료되고 난 이후와 띄워지기 이전 비활성상태로 있는다)

 * 상태 변화 모니터링 : 액티비티가 자신의 전체수명full lifetime, 가시수명visible lifetime, 활성수명active lifetime 사이를 전이할 때 호출되는 일련의 이벤트 핸들러들을 제공한다.

* onCrete() : 전체 수명 시장 시 호출

* onRestoreInstanceState() : onCrete가 종료된 후 호출되며, UI 상태 복구에 사용

* onRestart() : 가시 수명으로 이어지기 전, 액티비티 처리를 위해 호출

* onStart() : 가시 수명 시작 시 호출

* onResume() : 활성 수명 시작 시 호출

* onSaveInstanceState() : 활성 수명 끄트머리에서 UI 상태 변화를 저장하기 위해 호출

* onPause() : 활성 수명의 끝에서 호출

* onStop() : 가시 수명의 끝에서 호출

* onDestroy() : 전체 수명의 끝에서 호출

* 전체 수명 : onCrete ~onDestroy  

* 가시 수명 : onStart ~ onStop

* 활성 수명 : onResume ~ onPause 

* 안드로이드 액티비티 클래스 : MapActivity, ListActivity, ExpandableListActivity, ActivityGroup

저작자 표시
Posted by 훈남, 밍공™

댓글을 달아 주세요

안드로이드의 HW configuration에서 LCD density라는 환경 설정 값을 가지고 있습니다. 기본적으로 이 값은 160입니다. (DEFAULT).

도넛 버전 이전에는 공식적으로 HVGA만 지원을 했고 도넛부터 WGVA등이 추가되었습니.

이와 함께 LCD density 120 (LOW) 240 (HIGH) 두 개가 추가되었습니다.

아래 이미지들은 WVGA 해상도에서 LCD density 160 240인 경우를 비교해 놓은 것입니다.

보시듯이 LCD density 240일 경우 즉 고해상도에 LCD의 물리적인 사이즈가 변경이 거의 되지 않으며 HVGA랑 거의 동일한 look을 가지게 됩니다.

LCD density 160일 경우 MID같이 LCD의 물리적인 사이즈가 매우 커졌을 때 유용한 형태 인 것으로 생각됩니다.

(왜 이렇게 되는가는 표 아래쪽에 설명을 첨부하였습니다.)


Lcd.density = 160

Lcd.density = 240

Home

<!--[endif]-->

<!--[endif]-->

Apps List

<!--[if !vml]-->

<!--[endif]-->

Settings

<!--[endif]-->

<!--[endif]-->

실제 DPI 정보와는 약간 다른 단위가 안드로이드에 사용이 되고 있습니다.

DIP (또는 DP)라는 것으로 Device Independent Pixel의 약자입니다.

이는 디바이스의 LCD 해상도가 변경이 되어도 GUI 요소들의 물리적인 크기를 동일하게 유지하기 위한 방법입니다.

LCD density 160일 경우, 1 DIP = 1 Pixel 이라는 공식이 성립됩니다. (안드로이드가 HVGA, 160에서 출발해서 그렇습니다.)

따라서 이 density 값이 240으로 변경되면 1 DIP = 1.5 Pixel이 됩니다.

기본 생성되는 WVGA 에뮬레이터가 density 240으로 설정되어 있는데, 이 때문에 아이콘들이나 이미지들이 늘어나 보입니다.

(기존 20DIP x 20DIP 크기의 이미지가 HVGA (160)에서는 20pixel x 20 pixel로 보이지만 WVGA (240)에서는 30pixel x 20pixel 로 보이기 때문입니다.)

따라서 실제 물리적인 LCD의 크기가 많이 커지지 않고 해상도만 커진다면, 고해상도에서 더 많은 pixel을 차지하게 되므로 GUI 요소들의 실제 크기는 유사하게 유지시킬 수 있습니다. (예를 들면 저해상도 고해상도에서 모두 1인치)

 

<출처 : http://songminseok.blogspot.com/2009/09/understanding-dip-on-android-platform.html>

저작자 표시
Posted by 훈남, 밍공™

댓글을 달아 주세요

환경설정 (Preferences)

Android / 2010/06/28 14:39

1. 환경설정 개요 (Preferences)

 

안드로이드 플랫폼은 Data를 저장하는 방법으로 환경설정(이하 Preferences), 파일, Local DB, 네트워크를 제공한다.

 

그 중 Preferences는 가장 간단하게 정보를 저장하는 방법(mechanism)을 제공하며, App이나 그 컴포넌트 (Activity, Service 등)의 환경 설정 정보를 저장/복원하는 용도로 사용된다.

 

 

▌Preferences의 형태▐

안드로이드에서 Preferences는 ListView의 형태로 표현되며 쉬운 Preferences의 구현을 위해 PreferenceActivity 클래스를 제공한다. PreferenceActivity 클래스는 XML 기반의 Preference 정의 문서를 통해 App 파일 저장소에 Preferences 파일을 생성하고 사용하는 방식으로 작동한다. (참고: 일반 Activity를 사용해 ListView형태의 Preference Activity가 아닌 커스텀 Preference Activity를 구현 할 수도 있지만 (Container + 각종 UI 위젯 사용) 이 글에서는 그 방법에 대해 다루지 않으려고 합니다)

 

 

▌Preferences 데이터 저장▐

Preferences를 위한 데이터 저장 시 사용되는 자료구조는 Map 방식이다. 즉 키(key)-값(value) 한 쌍으로 이루어진 1~n개의 항목으로 구성된다. 키(key) 는 String 타입으로, 말 그대로 각 데이터에 접근할 수 있게 하는 유일한 구분자며, 값(Value)은 기본 자료형 (int, boolean, string 등) 기반의 데이터로 구성된다. 다음은 Map 데이터 구조의 한가지 예이다.

 키(Key) - String 형
 값(Value) - 기본자료형
 Font
 "Noraml"
 FontSize  20
 FontColor  FFFFFFFF
 ... ...
 ... ...

 

위와 같은 Preferences데이터는 안드로이드 디바이스의

data/data/App 패키지 이름/shared_prefs/

경로에 XML형태의 파일로 생성된다. xml 파일 이름은, 파일 생성/접근을 위해 어떤 메서드를 사용하느냐에 따라 시스템이 지정 할 수도 있고, 개발자가 임의의 파일 이름을 지정할 수도 있다.

 

 

참고로, 안드로이드에서 Preferences 데이터 파일을 다수의 App간에 공유하는 것은 기본적으로 불가능 하게 디자인 되어 있다. (참고: 여기서 불가능하다는 뜻은 Preferences Framework에서는 타 App의 환경 설정 파일에 접근할 수 있는 메서드를 제공하지 않는다는 뜻이다. 그럴 필요가 있을지 모르겠지만, 굳이 접근해야 한다면 Preferences 파일 생성 모드를 MODE_WORLD_READABLE로 설정해 guest가 파일을 쓰고 읽을 수 있도록 하고(위에서 MyCustomePref.xml 처럼) Preferences 데이터 파일을 파일 스트림을 통해 읽어와 직접 파싱하고 사용할 수 있는 편법이 있긴 하다)

 

XML파일을 디바이스로부터 추출해 열어보면 Preference 데이터가 다음과 같은 형식으로 저장되어 있음을 볼 수 있다.

view source
print?
1 <?xml version='1.0' encoding='utf-8' standalone='yes' ?>
2 <map>
3     <boolean name="GreetingMsg" value="true" />
4     <boolean name="sub_checkbox" value="true" />
5     <string name="AdditionalMsg">tigerwoods.tistory.com</string>
6     <string name="TextColor">FF00FF00</string>
7     <string name="Ringtone">content://settings/system/ringtone</string>
8 </map>

 

 

Preferences 구현 시 위와 같은 XML 기반 Preferences 데이터 파일을 File I/O API를 사용해 직접 생성/사용 하는 것은 아니다. 안드로이드는 Preferences구현/운용을 위해 android.preference 패키지 및 몇 가지 유용한 클래스/인터페이스(PreferenceActivity, SharedPreferences 등)를 제공하는데, 그것들의 도움을 받으면 손쉽게 Preferences를 구현/운용 할 수 있다.

 

 

▌Preferences 구현▐

안드로이드에서는 Preference 구현을 위해 많은 관련 클래스를 제공하기 때문에 그 클래스들을 적절히 이용하여 다음과 같이 몇 가지 단계만 추가하기만 하면 쉽게 프로젝트에 Preferences 기능을 추가 할 수 있다.

  • 프로젝트 내 어떤 환경정보를 Preferences로 관리 할지 설계
  • 위 설계에 따라 Preferences XML 문서를 작성하고 프로젝트 리소스로 공급 (\res\xml\ 밑)
  • 작성된 Preferences XML문서를 사용하는 PreferenceActivity 구현
  • Preferences가 필요한 Activity로부터 PreferenceActivity를 호출 (Intent 이용)
  • App이 다시 실행될 때 이미 저장된 Preference데이터 파일이 있다면 onResume()과 같은 callback내부에서 환경 설정 값 설정을 불러와 사용

 

위에 나열된 사항 이외에 Preference 데이터 파일의 생성, 데이터 변경 이벤트 listener, 데이터의 저장과 같은 부분은 PreferenceActivity 클래스가 자동으로 관리해 줌으로 개발자는 별로 신경 쓸 필요가 없다. (참고: PreferenceActivity를 사용하지 않고 일반 Activity로 구현한다면 안드로이드가 제공하는 여러 Preferences 관련 클래스 등을 이용해 파일 생성, 이벤트 listener, 저장 등을 직접 구현 해야 한다.)

 

그럼 위 Preference 구현 5단계 중 두 번째인 Preference XML 문서 작성부터 한 번 살펴보자.

 

 

 

 

2. Preference XML 문서 작성하기

 

Preference XML 문서를 작성하기 전에 문서를 구성할 Preferences 관련 클래스들에 관해 약간의 지식이 필요함. 이 글 끝 부분에 "참고. Preference XML 문서 작성시 사용되는 클래스" 단락에 간단한 클래스 설명과 중요 XML 속성, 메서드 등이 설명 되어 있음으로 참고.

 

Preferences XML 문서는 프로젝트 폴더\res\xml\파일이름.xml의 위치에 생성 한다. xml 파일의 이름은 개발자 임의로 지정할 수 있으며 추 후 code 상에서 R.xml.파일이름으로 접근 할 수 있다.

 

이렇게 생성된 XML 문서 내부를 여러 Preference 관련 클래스를 사용해 정의 해야 하는데, 이 글에 포함된 예제 프로젝트에서 사용된 Preference XML 문서를 살펴보면 다음과 같다.

소스 펼치기

 

 

그럼 settings.xml에서 사용된 요소들을 하나씩 분석해 보자

 

 

<PreferenceScreen>

Preferences XML 문서의 root 요소는 항상 <PreferenceScreen>이며 root 요소 내부에는 반드시 xmlns 속성 (xmlns:android=http://......)을 정의해 주어야 한다.

 

root로 사용된 <PreferenceScreen>는 child를 포함하는 container 역할을 하며, PreferenceActivity에게 Preferences 계층 구조를 전달하는 역할을 한다. root로 사용된 <PreferenceScreen>은 container역할 만 하고 자기 자신은 화면에 직접 표현이 안됨으로 title, summary 속성을 지정할 필요가 없다.

 

key 속성에 지정된 문자열은 추 후 code에서 이 preference 계층 구조 내부의 특정 요소를 찾을 수 있는 키 값이 된다.


Preferencescreen root = (PreferenceScreen)getPreference("preference_root");

CheckBoxPreference cb = (CheckBoxPreference)getPreference("checkbox");

 

 

<CheckBoxPreference> & <EditTextPreference>

Root <PreferenceScreen> 밑에 처음 나오는 두 개의 child이며, XML에 추가된 순서대로 Preference view에 표시된다.

각 아이템은 key, title, summary 속성이 지정되어 있으며, checkbox의 경우 초기 설정이 check 상태로 지정되어 있다.

<EditTextPreference> 같은 경우 DialogPreference로부터 상속하며, 클릭 시 별도의 다이얼로그 창을 popup 한다.

 

 

<PreferenceCategory>

예제는 총 2개의 <PreferenceCategory>가 있으며 첫 번째는 <ListPreference>와 <RingtonePreference>를 하나의 Category로 묶는다. 예제 XML의 34번째 라인에 보면 두 번째 Category도 지정되어 있으며 <PreferenceScreen>을 Catefory 멤버로 가지고 있다.

 

<PreferenceCategory>에서 title속성은 다른 Preference 객체와 같이 제목을 표시하지만, summary는 지정되어도 화면에 표시 되지 않는다.

 

또, 첫 번째 category의 속성 중 android:enabled 속성이 false로 지정되어 있음으로 Preference초기 실행 시 child인 <ListPreference>와 <RingtonePreference>는 비활성화 상태로 표현된다. 이와 같이 여러 Preference 아이템을 하나의 category로 묶으면 그룹 속성을 지정하는 것이 가능하다. (Preference의 마지막 항목, checkbox를 check하면 첫 번째 category를 활성화 함)

 

 

<ListPreference>

다른 항목들과 마찬가지로 key, title, summary가 설정되어 있으며, entries 속성에는 사용자에게 보일 ListView 아이템을 지정하며, entryValues속성에는 컴퓨터가 처리할 처리 할 정보를 제공한다. 예를 들면 entries – "Red", "Green", "Blue" 등 사람이 읽을 수 있는 값을 제공하고, entryValues에는 "FFFF0000", "FF00FF00", "FF0000FF" 등 컴퓨터가 사용할 정보를 제공한다.

 

또, android:defaultValue 속성이 "FFFFFFFF"으로 지정되어 있어 사용자가 설정 값을 바꾸기 전까지는 "FFFFFFFF" (흰색)이 기본 값으로 사용된다.

 

 

<RingtonePreference>

key, title, summary가 지정되어 있으며, showDefault와 showSilent가 true로 설정되어 Default 항목과 Slient 항목이 리스트에 표시된다. (<RingtonePreference>는 사용자가 지정한 정보를 바탕으로 Ringtone 설정 기능을 제공하는 Activity들을 찾는 Intent를 발생 시킨다. 디바이스에 여러 종류의 ringtone과 ringtone 관련 activity를 제공하는 app이 설치되어 있다면 더 많은 ringtone 옵션이 화면에 표시 될 수도 있다)

 

 

<PreferenceCategory>

두 번째 그룹으로 CheckBox를 별도의 화면에 표현하는 <PreferenceScreen> child를 포함.

 

 

<PreferenceScreen>

<PreferenceScreen>가 child 요소로 사용된 경우. Preferences에서 하나의 아이템으로 표현되기 때문에 title, summary가 지정되어 있다. 이 아이템을 선택하면 별도의 Preference 창 (dialog 기반)이 Popup한다.

 

 

<CheckBoxPreference>

key, title이 지정되어 있으며, summayOn과 summaryOff에는 각각 check상태의 도움말과 uncheck상태의 도움말이 설정 되어 있다.

 

 

 

 

3. XML + PreferenceActivity이용해 Preference 구현하기

 

작성된 Preference XML 파일을 화면에 표현 가능한 Preference로 만드는데 핵심적인 역할을 하는 것이 바로 PreferenceActivity이다. 전에 살펴본 적이 있는 ListActivity, TabActivity와 마찬가지로 Activity로 상속하며, Preference를 화면에 표현하고 운영하는데 특화된 클래스이다.

 

PreferenceActivity는 Preference 생성/운영에 도움이 되는 다음과 같은 편리한 기능이 구현되어 있다.

  • XML부터 Preference 계층 구조를 전달 받는 메서드 제공
  • 타 Activity의 Preference 계층 구조를 받아오는 메서드 제공
  • 제공된 Preference 계층 구조를 ListView 형태로 자동 구성/표현
  • 제공된 Preference 계층 구조에 따라 디바이스에 Preference 데이터 파일 자동 생성
  • 사용자가 변경한 사항들을 Preference 데이터 파일에 자동 저장

 

 

PreferenceActivity를 이용해 Preference를 구현하려면 크게 두 가지 단계만 거치면 되는데 다음과 같다. (물론 PreferenceActivity도 Activity 생명 주기를 따르기 때문에 onPause(), onResume() 메서드 같은 생명 주기 관련 callback의 구현도 신경 써야 하지만 여기서는 Preference를 구현하는 최소한의 기능만 설명한다)

  • PreferenceActivity를 상속하는 커스텀 클래스 정의.
  • onCreate()에 내부에서 Preference 계층 구조를 가져오는 메서드 호출.

 

위에서 두 번째 구현 순서로 설명된 Preference 계층 구조를 가져오는 메서드는 2개가 제공된다.

우선, \res\xml 밑의 Preference XML로부터 Preference 계층 구조를 얻어올 수 있는 메서드는 다음과 같다.

void addPreferencesFromResource(int)

Parameter:

  • int: Preference XML Resource. (예. R.xml.preferences)

 

두 번째로 타 Activity가 사용하는 Preference 계층 구조를 가져와 적용 시킬 수도 있는데, 이 때 사용되는 메서드는 다음과 같다.

(이 부분은 해결이 안 되는 중요한 버그가 있습니다. main preference까지는 잘 가져와 지는데 별도의 dialog를 띄우는 Preference 아이템을 클릭하면 WindowsManager가 BadTokenException을 발생합니다. 자세한 증상은 첨부된 예제 프로젝트에서 확인하시고, 혹시 해결 방법을 아시는 분은 꼭 댓글 부탁 드립니다)

void addPreferencesFromIntent(Intent)

Parameter:

  • Intent: Preference 계층 구조를 제공할 Activity를 지정하는 Intent

 

구현이 완료된 PreferenceActivity는 타 Activity로 부터 호출 되면 ListView 형태의 Preference 화면을 사용자에게 제공하고, 사용자가 정보를 수정하면 자동으로 Preference 데이터에 저장 하게 된다.

 

PreferenceActivity가 많은 편의 기능을 제공하지만 저장된 설정 복원은 개발자의 몫이다. 즉, 포함된 App이 다시 실행될 때, 기존에 저장된 Preferences설정 값을 Preference 데이터 파일로부터 읽어와 App에 적용 시키는 작업 (ex. App시작 시 Preference 파일에 저장된 폰트 색깔 등을 로드 해 App에 적용시키는)은 개발자가 직접 구현해 주어야 한다. 이를 위해 다음 단락에는 저장된 Preference 데이터 파일에 접근하여 저장된 정보를 가져오는 방법에 대해 알아본다.

 

 

 

 

4. Preference 데이터 파일로부터 환경 복원하기

 

안드로이드에서는 SharedPreferences 인터페이스를 이용해 저장된 Preferences 데이터 파일에 접근한다.

 

 

▌SharedPreferences 인터페이스 얻기▐

 

안드로이드 코드 내에서 SharedPreferences 인터페이스를 얻는 방법은 다음 나열된 세 개의 메서드를 통해서 가능하다. 



SharedPreferences Activity.getPreferences(int)

Parameter:

  • int: Preference 데이터 파일의 생성 시 접근 권한을 설정. Context클래스에 상수로 선언된 MODE_PRIVATE, MODE_WORLD_READABLE, MODE_WORLD_WRITABLE을 설정 가능. MODE_PRIVATE는 지금 App 만 접근 가능하도록 파일을 생성하며 (_rw_rw____), MODE_WORLD_READABLE/WRITABLE은 타 App에서도 파일을 읽고/쓸 수 있도록 생성한다 (_rw_rw_r__ 또는 _rw_rw__w_ 또는 |를 이용해 두 속성을 모두 지정하면 _rw_rw_rw_)

Return:

  • SharedPreferences: 메서드가 호출되는 Activity 클래스의 이름으로 저장된 Preference 데이터 파일의 SharedPreferences 인터페이스를 리턴. 같은 이름의 Preference 데이터 파일이 없을 경우 새로 생성

 

예를 들면 Activity를 상속하는 A, B라는 클래스 이름의 커스텀 Activity가 정의 되어 있다. A 내부에서 getPreference를 호출할 경우 디바이스의 Preference 저장 위치(data/data/패키지이름/shared_prefs/)에 A.xml 이라는 Preference 데이터 파일을 검색하고 파일이 존재 한다면 해당 파일에 대한 SharedPreferences 인터페이스를 리턴 하며, 파일이 존재하지 않을 경우에는 A.xml 파일을 생성한 후 생성한 파일에 대한 SharedPreferences 인터페이스를 리턴한다. 마찬가지로, B 내부에서 getPreference를 호출할 경우 디바이스에서 B.xml 파일을 검색 후 해당 파일에 대한 SharedPreferences 인터페이스를 리턴 한다 (없으면 파일 생성 후 인터페이스 리턴).


 

SharedPreferences Context.getSharedPreferences(String, int)

Parameter:

  • String: 사용(생성)할 Preference 데이터 파일의 이름을 지정
  • int: 생성될 Preference 데이터 파일의 생성 시 접근 권한을 설정

Return:

  • SharedPreferences: 첫 번째 인자로 전달되는 문자열과 일치하는 이름의 Preference 데이터 파일의 SharedPreferences 인터페이스를 리턴. 만약 같은 이름의 파일이 없다면 파일을 새로 생성하고 생성된 파일에 대한 SharedPreferences 인터페이스를 리턴

 

한가지 참고할 사항은 이 메서드를 통해 개발자가 생성/사용될 Preference 데이터 파일의 이름을 임의로 설정할 수 있다는 것인데, 예를 들어, A라는 Activity에서 getSharedPreferences("initial_setting", MODE_PRIVATE)라는 메서드를 실행한다면, preference framework는 /data/data/패키지/shared_pref/ 밑에서 initial_setting.xml이라는 파일을 검색하고 없다면 이를 새로 생성 후 initial_setting.xml에 대한 SharedPreferences 인스턴스를 리턴 하게 된다..

 

제일 처음에 설명한 Activity.getPreferences(int)도 실제로는 자기자신을 호출한 Activity(또는 컴포넌트)의 이름과 입력된 int 형 인자를 가지고 본 메서드를 호출하는 형태로 구현되어 있다.




Static SharedPreferences PreferenceManager.getDefaultSharedPreferences(Context)

Parameter:

  • Context: 사용하기 원하는 SharedPreferences 인터페이스를 포함하는 Context 지정

Return:

  • SharedPreferences: 인자로 지정된 Context (app 구동 환경)가 기본으로 생성하는 Preference 데이터 파일에 대한 SharedPreferences를 리턴

 

이 메서드는 App level의 기본 Preference 데이터 파일을 생성/사용하는데 사용된다. 예를 들어 com.holim.test.aaa 라는 패키지에 포함되는 A Activity에서 본 메소드를 호출 하면 Preference 프레임웍은 /data/data/패키지이름/shared_pref/com.holim.test.aaa_preferences.xml 이라는 Preference 데이터 파일을 생성한다. 전달된 Context 인자에 따라 패키지이름_preferences.xml 형태로 생성/사용할 Preference 데이터 파일의 이름이 시스템에 의해 자동으로 지정되게 되기 때문에, 호출되는 위치가 어디이든 같은 Context를 인자로 전달해 호출한 getDefaultSharedPreferences(…)메서드는 항상 같은 SharedPreferences 인스턴스를 리턴한다.

 

한가지 참고할 사항은 본 메서드는 static 메서드이기 때문에 메서드를 제공하는 PreferenceManager 클래스를 따로 생성할 필요 없이 다음과 같이 사용하면 된다.

SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences(this);

 

 

이와 같이 여러 메서드를 사용해 얻어온 SharedPreferences 인터페이스로 무엇을 할 수 있는 지 알아 보자. 다음은 SharedPreferences 인터페이스가 제공하는 중요 메서드들이다.

 

 

▌SharedPreferences 인터페이스▐

 

SharedPreferences 인터페이스가 제공하는 기능은 다음과 같다.

  • 디바이스에 저장되어 있는 Preference 데이터 파일로부터 데이터를 추출하는 여러 메서드
  • Preference 데이터를 수정하는 방법을 제공하는 Editor 내부 인터페이스
  • Preference 데이터가 변경되었을 때 호출되는 callback 인터페이스

 

중요 메서드

SharedPreferences.Editor edit() – SharedPreferences가 연결된 Preference 데이터 파일을 수정 할 수 있게 여러 메서드를 제공하는 Editor 인터페이스 리턴. Editor 인터페이스는 자료 수정을 완료 한 후 Editor.commit() 메소드를 사용해야 파일에 변경내용이 저장됨.

void registerOnSharedpreferenceChangeListener(…) – Preference 변경 이벤트 Listener 등록

void unregisterOnSharedPreferenceChangeListener(…) – 위에 등록한 이벤트 Listener 등록 해지

Map <String, ?> getAll() – 모든 Preferences 값을 Map 자료형으로 리턴

boolean contains(String) – 인자로 제공되는 문자열과 같은 key의 Preference 항목이 있으면 true 리턴

타입 get타입(String, 타입) – Boolean, Float, Int, Long, String 형 메서드가 있으며 첫 인자는 데이터를 가져올 Key 값이며, 두 번째 인자는 찾는 preference 데이터가 존재하지 않을 때 리턴 할 값이다.

Boolean isMarried = sharedPref.getBoolean("결혼여부", false);

int fontSize = sharedPref.getInt("폰트사이즈", 20);

 

중요 인터페이스

  • SharedPreferences.Editor – Preference 파일에 저장된 항목을 수정/제거 할 수 있는 여러 메서드를 제공하는 인터페이스
  • SharedPreferences.OnSharedPreferenceChangeListener – Preference 데이터가 변경되었을 때 호출되는 callback 인터페이스

 

 

예제 프로젝트 중 MainActivity.java의 onCreate(…)와 onPause(…)메서드에서 보면 지금까지 설명한 SharedPreferences 인터페이스 얻기와 인터페이스가 제공하는 여러 메서드를 사용해 Preference 데이터 파일로부터 저장된 정보를 가져와 사용하는 것을 볼 수 있다.


MainActivity.onCreate()

소스 펼치기

 

MainActivity.onResume()

소스 펼치기

 

 

 

 

참고. Preference XML 문서 작성시 사용되는 클래스

 

전 글들에서 다루었던 XML을 이용한 UI메뉴 구성에서도 봤듯이

XML을 이용하면 디자인과 Logic을 분리 시킬 수 있어 간결한 코드의 구성이 가능할 뿐 아니라 현지화/유지보수 등 작업을 하는데 훨씬 편리 할 수 있음으로 권장되는 구현 방식 이라고 설명 한 적이 있다.

 

Preference에서도 마찬가지로 XML을 이용해 Preferences 구조를 쉽게 정의할 수 있다.

 

Preference XML 문서 작성시 android.preference 패키지 밑의 여러 클래스가 사용되는데 패키지 내부의 중요한 클래스의 상속 구조는 다음과 같다.

 

 

붉은 색 사각형 내부의 클래스가 Preferences 과 직접적으로 연관이 있는 클래스이며, 그 중 Preference 클래스를 비롯한 하위 클래스들이 XML Preference 문서 작성에 사용된다.

 

그럼 Preference 클래스부터 한번 살펴보자

 


 

▌Preference 클래스▐

여러 Preference 관련 클래스의 최상위 부모 클래스 이므로, 제공하는 XML 속성, 메서드는 자식 Preferences 관련 클래스에서도 모두 사용할 수 있다. XML 내부에서 직접적으로 사용되지는 않는다.

 

중요 XML 속성

  • android:key – Preferences 데이터 저장/불러올 때 사용되는 키(key) 지정
  • android:title – Preference 항목의 제목을 지정
  • android:summary – Preference 항목을 자세히 설명하는 문자열 지정
  • android:enabled – Preference 항목의 활성화 비활성화 여부 지정 (true/false)
  • android:selectable – Preference 항목의 선택 가능 여부 결정 (true/false)
  • android:order – Preference 항목이 표시되는 순서를 결정 (0-based 정수 사용: 낮은 값 먼저 보임). 순서가 명시적으로 지정되지 않는다면 XML에 정의된 순서대로 표시됨

 

중요 메서드

  • void setKey/Title/Summary(…) – Preference 항목의 키/제목/설명을 지정
  • void setEnabled(boolean) - Preference항목의 활성화/비활성화 여부 지정
  • void setSelectable(boolean) – Preference 항목의 선택 가능 여부 결정
  • void setLayoutResource(int) – Preference 항목에 표시할 View를 R 클래스로부터 지정
  • void setOnPreferenceChangedListener(…) – Preference 항목에 변화가 있으면 호출될 callback을 지정
  • void setOnPreferenceClickListener(…) – Preference 항목에 click 이벤트가 발생하면 호출될 callback을 지정

 

중요 인터페이스

  • Preference.OnPreferenceChangeListener - 사용자가 Preference를 변경하였을 때 호출되는 callback에 대한 인트페이스
  • Preference.OnPreferenceClickListener - 사용자가 Preference를 클릭하였을 때 호출되는 callback에 대한 인터페이스

 

 


▌PreferenceGroup 클래스▐

 

Preferences를 구성하는 객체들을 담을 수 있는 Container 클래스. PreferenceCategory와 PreferenceScreeen을 파생. XML 내부에서 직접적으로 사용되지는 않음.

 

중요 메서드

  • boolean addPreference(Preference) – 새로운 Preference 항목을 그룹에 추가. 추가 성공/실패 리턴.
  • Preference findPreference(String) – 인자로 전달되는 문자열과 같은 key값을 갖는 group 내 (자기자신포함) Preference 항목 리턴
  • Preference findPreference(int) – 인자(0-based정수)에 명시된 위치의 Preference 항목 리턴. 기본적으로 가장 처음 추가된 항목이 index 0
  • void removeAll() – 이 그룹 내 모든 Preference 항목을 삭제함
  • void removePreference(Preference) - 인자로 전달된Preference 항목을 삭제함
  • void setEnabled(boolean) – 그룹 전체의 활성화/비활성화 여부 지정
  • void setOrderingAsAdded(boolean) – true일 경우 그룹에 추가된 순서로 표현. false일 경우 Preference아이템 내 순서 정보가 있으면 그걸 따르고 순서 정보가 없으면 Preference 아이템의 title을 이용해 알파벳순 정렬.

 


 

▌PreferenceScreen 클래스▐

 

PreferenceGroup에서 파생하며, 실제로 Preference XML 문서 내부에 사용 되는 클래스이다. 여러 Preference 구성 요소를 담을 수 있는 root container역할을 하며 Activity에 표현될 Preference의 계층구조를 나타내는 클래스이다. PreferenceActivity에 전달되어 이 클래스의 인스턴스가 포함하는 것들을 화면에 표현한다.

 

이 클래스가 Preference XML 문서에서 사용될 때는 다음과 같이 두 가지 용도로 사용된다.

  • Preference XML 문서의 root 요소 사용 시 - 경우에는 PreferenceActivity에 전달되어 preference의 전체 구조를 전달하는 용도로 사용. 이 경우 자기 자신은 화면에 표현 안되고 child 요소를 포함하는 Container의 용도로 사용됨 (XML UI에서 Containter는 화면에 표현 안되고 것과 같은 의미)
  • Preference XML 문서에서root가 아닌 child 요소로 사용 시 - Preference 아이템 중 하나로 취급. Preference 아이템 중 하나로 화면에 표시되며, 클릭 시 별도의 preference 화면으로 이동

 

!!! 그림 (main pref. -> sub pref)

 


 

▌PreferenceCategory 클래스▐

 

Preferences를 구성하는 객체들을 특정 category별로 분류 할 수 있게 하는 클래스. 중요한 XML 속성이나 메서드 없음

!!! 그림 (category 분류)

 

 


▌DialogPreference 클래스▐

 

모든 dialog 기반 Preference 객체의 부모 클래스. Preference 화면에는 링크만 표시되고, 링크를 클릭했을 때 실제 Preference를 컨트롤 할 수 있는 Dialog가 popup한다.

!!! 다이얼로그 그림

 

중요 XML 속성

  • android:dialogIcon – Dialog의 Icon 지정
  • android:dialogTitle – Dialog의 제목 지정
  • android:dialogMessage – Dialog 내에 표시될 문자열 내용 지정
  • android:negativeButton – 부정 버튼에 표시될 Text설정 (취소, cancel 등)
  • android:positiveButton – 긍정 버튼에 표시될 Text 설정 (적용, OK 등)

 

중요 메서드

  • void setDialogIcon(Drawable) – Dialog의 Icon 지정
  • void setDialogTitle(…) – Dialog의 제목 지정. 문자열 직접 지정 또는 문자열 리소스 사용
  • void setDialogMessage(…) – Dialog 내에 표시될 문자열 내용 지정
  • void setPositiveButtonText(…) – 부정 버튼에 표시될 Text설정 (취소, cancel 등)
  • void setNegativeButtonText(…) – 긍정 버튼에 표시될 Text 설정 (적용, OK 등)

 


 

▌EditeTextPreference 클래스▐

 

DialogPreference로부터 상속하며, 사용자로부터 문자열을 입력 받아 저장 하기 위한 Preference 아이템을 구현한 클래스.

 

중요 메서드

  • EditText getEditText() – Dialog가 포함하는 EditBox인스턴스를 리턴
  • String getText() – SharedPreferences 객체로부터 저장된 문자열 리턴
  • void setText() – SharedPreferences에 문자열 저장

 


 

▌ListPreference 클래스▐

 

DialogPreference로부터 상속하며, Dialog기반의 ListView 위젯에 미리 제공되는 문자열들을 표현하고 사용자가 그 문자열 중 하나를 선택하여 설정 값을 지정할 수 있도록 구현한 클래스.

 

중요 XML 속성

  • android:entries – ListView의 각 raw에 표현될 문자열을 array 리소스를 통해 공급. 사용자(human)를 위한 정보.
  • android:entryValues – ListView의 특정 raw가 사용자에 의해 선택되었을 때 프로그램 내부적으로 처리 할 문자열 data를 array 리소스 형식으로 제공. 컴퓨터가 처리 하기 위한 정보. (ex. 남/여: 사람을 위한 정보 -> 0/1: 컴퓨터를 위한 정보)
  • android:defaultValue – 초기 선택 항목 지정. (0-based 정수)

 

중요 메서드

  • CharSequence[] getEntries() – ListView의 각 row에 표현될 문자열들을 리턴 (사용자 위한 정보)
  • CharSequence[] getEntryValues() – Entry(사람을 위한 정보)와 연계된 컴퓨터가 처리할 문자열들을 리턴
  • void setEntries(…) – ListView의 각 row에 표현할 문자열 지정. Array리소스 또는 CharSequence[] 전달
  • void setEntryValues(…) – 컴퓨터가 처리할 문자열 지정. Array또는 CharSequence[] 전달

 


 

▌CheckBoxPreference 클래스▐

 

CheckBox 기능의 Preference 아이템을 구현한 클래스. SharedPreferences에 boolean 값으로 정보 저장

 

중요 XML 속성

  • android:summayOn – CheckBox가 check상태일 때 사용자에게 보일 안내문
  • android:summaryOff – CheckBox가 uncheck 상태일 때 사용자에게 보일 안내문

 

중요 메서드

  • boolean isChecked() – 현재 check/uncheck 상태 리턴
  • void setChecked(boolean) – CheckBox를 program 상에서 check/uncheck 함
  • void setSummaryOn(…) – CheckBox가 check상태일 때 사용자에게 보일 안내문 설정. String 리소스나 CharSequence 인스턴스 전달
  • void setSummaryOff(…) – CheckBox가 uncheck상태일 때 사용자에게 보일 안내문 설정

 


 

▌RingtonPreference▐

 

사용자가 디바이스에서 제공하는 전화 벨 소리를 지정할 수 있게 구현된 클래스. Intent를 이용해 어떤 벨 소리 Picker를 화면에 표시할 지 결정함.

 

중요 XML 속성

  • android:ringtoneType – 어떤 종류의 벨 소리 종류를 선택 가능하게 할지 지정. ringtone, notification, alarm, all 중에 하나 또는 복수(| 사용)개 지정 가능
  • android:showDefault – Default 벨소리 항목 표시 여부 결정 (true/false)
  • android:showSilent – 무음(Silent) 항목 표시 여부 결정 (true/false)

 

중요 메서드

  • setRingtoneType(int type) – XML 속성 중 ringtoneType에 대응. RingtoneManager 클래스에 선언되어 있는 상수 TYPE_RINGTONE, TYPE_NOTIFICATION, TYPE_ALARM, TYPE_ALL 중 하나 또는 복수(|사용) 전달
  • setShowDefault(boolean) – XML showDefault 속성에 대응
  • setShowSlient(boolean) – XML showSilent 속성에 대응

 


 

PreferenceManager 클래스

 

Activity나 XML로부터 Preferences 계층구조의 생성을 돕는 helper 클래스이지만 이 클래스를 이용하여 직접 Preferences를 구성하기보다는 PreferenceActivity.addPreferenceFromResource(int) 또는 PreferenceActivity.addPreferenceFromIntent(Intent)를 사용하는 것이 일반적이다.

 

혹시, PreferenceActivity를 사용하지 않고 Activity를 이용해 직접 Preferences 화면을 구성해야 한다면 필요한 클래스이다.

 

중요 메서드

  • Preference findPreference(CharSequence) – 인자로 전달되는 Key값을 가지는 Preference 항목의 인스턴스를 가져옴
  • SharedPreferences getDefaultSharedPreferences(Context) – 제공되는 context가 기본으로 사용하는 Preference파일로부터 SharedPreferences인스턴스 생성해 리턴
  • SharedPreferences getSharedPreferences() – this객체가 사용하는 context와 연결될 Preference파일로부터 SharedPreferences 인스턴스 생성해 리턴
  • void setDefaultValues(Context, int resId, boolean) – 제공되는 context가 사용하는 SharedPreferences를 두 번째 인자로 제공되는 XML 리소스에 정의된 기본 속성값들로 설정 함. 세 번째 인자가 false 일 경우엔 이 메서드가 전에 실행된 적이 있다면 무시하고, true일 경우 전에 실행 여부화 상관없이 재 실행된다. 참고: 마지막 인자를 true로 지정 했다고 해서 이 메서드를 이용해 Preferences를 바로 초기화 할 수 있는 것은 아니고, SharedPrefernces.clear() 메서드를 사용해 Preferences 항목을 모두 삭제 후 이 메서드를 사용해 XML에 지정된 본래의 값으로 Preferences를 초기화 할 수 잇다.
저작자 표시
Posted by 훈남, 밍공™

댓글을 달아 주세요

1. Activity의 4가지 주요 상태 (4 essential states of Activity)

 

Active/Running 상태

Activity A가 화면의 가장 앞(foreground)에 있어 사용자가 직접 볼 수 있고, 포커스를 가지고 있는 상태.

다시 말하자면 입/출력이 가능한 상태.

 

 

 

Pause 상태

Active상태의 activity A가 화면의 foreground를 새로 점유한 activity N에게 포커스를 잃었지만 아직은 A의 일부가 보이는 상태 (foreground를 획득한 activity N이 화면 전체를 사용하지 않거나, 반투명하게 구현 되어 있을 때).

 

 

 

Stop 상태

Active/Pause상태의 activity A가 full-screen크기의 activity N에게 화면 foreground를 선점 당한 상태.

 

 

 

Killed (Dead) 상태

Activity A가 생성되지도 않았거나 생성 후 소멸된 상태.

 

 

 

 

2. Activity의 상태 변이와 callback 메소드

 

Activity의 상태변이도

 

위에서 설명한 4가지 Activity상태간 변이 시에 코드의 흐름을 나타낸 그림이다. (클릭하면 크게 보임)


 

참고. onRestoreInstanceState(Bundle)onSaveInstanceState(Bundle)메소드들은 life cycle 에 직접적으로 관여하는 메소드는 아니며 상황에 따라 호출이 생략될 수 있다. 다음 단락: Activity의 강제 종료와 복구에서 자세히 설명.

 

 

위의 그림에서 파란색 실선은 정상적인 Actvity의 흐름이며 붉은색 점선은 비정상적인 Activity의 흐름이다.

위 그림을 이용하면 수 많은 Activity의 상태변이 case들에서 어떤 callback들이 어떤 차례로 호출되는지 쉽게 볼 수 있다.

 

예를 들어, Activity가 처음 실행돼서 사용자에게 사용되다 정상 종료 된다면 다음과 같은 callback이 차례로 호출된다.

onCreate(Bundle) -> onStart() -> onResume() -> onPause() -> onStop() -> onDestory()

 

 

또, Running상태의 Activity A가 다른 Activity B에게 완전히 가렸다 A가 다시 foreground로 와서 사용자에게 사용되는 경우는 다음과 같은 callback이 차례로 호출된다.

onSaveInstanceState(...) -> onPause() -> onStop() -> onRestart() -> onStart() ->onResume()

 

 

마지막 예로, 화면의 일부가 가린 pause 상태의 Activity A가 system 자원(메모리)의 부족으로 system에 의해 강제로 종료 당했다가 system 자원의 여유가 생겨 다시 복구 될 때는 다음과 같은 callback이 차례로 호출된다.

강제종료 -> onCreate(…) -> onStart() -> onRestoreInstanceState(...) -> onResume()

 

 

 

Life Cycle 관련 Callback 메소드 분석

 

Activity의 상태변이 시 호출되는 callback들을 각각 자세히 설명하면 다음과 같다. (클릭하면 크게 보임)



 

한가지 중요한 것은 위의 callback을 오버라이딩 할 때는 다음과 같이 super클래스의 원래 callback을 먼저 호출하여야 한다.

protected void onPause() {
super.onPause();
...
}



 

 

3. Activity의 강제 종료와 복구

 

System에 의한 Activity의 강제 종료

 

스마트폰 플랫폼은 PC와 달리 제한된 리소스(대표적으로RAM)을 가지고 있기 때문에 여러 가지 작업을 동시에 진행할 때 리소스 부족현상에 직면할 수 있다.

 

이는 심각한 문제를 유발 할 수도 있는데, 한가지 예를 들어 보자. 예를 들어 사용자가 이용하고 있는 게임 어플리케이션의 Activity A가 foreground서 사용자와 interact하고 있다고 치자. 이때 전화가 걸려오면 시스템은 incoming call Activity B를 foreground에 띄워 사용자에게 전화가 왔음을 알려야 한다. 하지만 만약에 A가 시스템의 리소스를 거의 전부 점유하고 있는 상황이라면 B Activity를 띄우는 것이 불가능 할 수 있다.

 

스마트폰에서 게임을 하는 것 보다 전화를 받는 Task가 훨씬 중요한 것이 일반적임으로, 이 경우 디바이스의 효율적인 운영이 이뤄진다고 볼 수 없고 이는 곧 user의 불편함으로 이어진다.

 

그래서 안드로이드에서는 여러 개의 Activity를 운영 중 시스템 리소스가 부족하면 특정 상태에 있는 Activity를 강제로 종료 할 수 있게 디자인 되어있다. Activity의 상태에 따른 강제 종료 우선 순위는 다음과 같다.

Running 상태: 절대 강제 종료 되지 않음

Pause 상태: 강제 종료 2순위

Stop 상태: 강제 종료 1 순위

 

전 단락의 life cycle 관련 callback 테이블을 보면 강제 종료 칼럼에 yes라고 표기된 onPause(), onStop(), onDestroy()가 있는데 이들 callback이 호출 된 뒤에는 Activity가 언제든지 강제 종료 될 수 있다는 뜻이다.

 

한가지 중요한 것은 onPause() callback이 실행 중에는 Activity는 아직 Running 상태이고 onPause()가 리턴 하자마자 Activity는 Pause상태가 되기 때문에 onPause() callback은 항상 return이 보장되는 반면 나머지 2 개의 callback, onStop(), onDestroy()이 실행 될 때는 Activity는 각각 Pause상태, Stop상태이기 때문에 return이 보장되지 않는다.

 

이런 이유(onPause() 이후에는 Activity가 강제 종료 당할 수 있음)로 onPause() callback에서 사용자가 진행하던 작업을 저장 하는 등의 강제 종료에 대비한 작업을 해주어야 한다.

 

 

 

강제 종료된 Activity의 복구

 

강제 종료된 Activity는 가동하는데 충분한 resource가 확보되면 (예를 들면 Activity A를 강제 종료 시켰던 Activity B의 종료 등) 자동으로 복구되지만, 한가지 작업이 이루어 지지 않는다면 사용자에게 심각한 불편을 초래할 수 있다. 다음과 같은 시나리오를 가정해 보자.

User가 계산기 어플리케이션의 Activity A를 통해 시간이 오래 걸리는 작업(예, 숫자 100개 더하기 중 50개를 더한 상황) 중에 전화가 걸려왔는데 시스템의 리소스 부족으로 incoming call Activity B를 띄울 수 없는 상황이 발생 했다고 쳐보자. 시스템은 A를 강제 종료 시켜 부족한 리소스를 확보하고 B를 사용자에게 보여줘 사용자가 전화를 받을 수 있게 한다. 전화 통화를 완료한 후 시스템은 강제종료 된 A를 자동으로 복구 했지만 사용자가 이미 수행하고 있던 작업(100개중 50를 더한 중간 결과)의 상태는 초기화 되어 버리고 사용자는 다시 처음부터 작업을 수행해야 한다.

 

위와 같은 불편을 막기 위해, 안드로이드의 Activity 클래스는 onSaveInstanceState(Bundle) 메소드와 onRestoreInstanceState(Bundle) callback 메소드를 제공한다.

 

우선 위의 Activity 상태변이도에서 본것과 같이,

onSaveInstanceState(Bundle)은 onPause()전에 호출되며 파라미터로 전달 받는 Bundle 인스턴스에 현재 activity의 상태를 저장하게 된다. 저장된 Bundle인스턴스는 시스템이 Activity를 자동으로 복원할 때 호출되는 onCreate(Bundle) -> onStart() -> onRestroreInstanceState(Bundle) -> onResume() callback 중 onCreate(…)onRestoreInstanceState(…) callback에 모두 파라미터로 전달 됨으로 양쪽 어디서건 사용해서 강제종료 되기 전의 상태로 Activity를 복구 시키면 된다.

 

한가지 참고할 사상은 onSaveInstanceState(Bundle)과 onRestroreInstanceState(Bundle)은 life cycle과 직접적으로 관련이 있는 callback이 아님으로 Activity의 상태 변화 시 항상 호출된다는 보장이 없다. 논리적으로 꼭 필요한 상황에서만 호출됨으로 Activity상태가 바뀔 때 예외 없이 호출 되어야 하는 루틴은 life cycle 관련 callback (onResume(), onPause() 등)에서 구현 하여야 한다.

 

예를 들면, 사용자가 Activity 를 디바이스의 BACK key 로 직접 종료하거나 Activity.finish() 메소드를 사용해 정상 종료되는 경우에는 Activity의 현 상태를 복구할 필요가 없기 때문에 onSaveInstanceState(Bundle) callback의 호출은 생략된다.

 

 

 

 

4. Activity 생명주기 예제 (Activity Life Cycle Demo)

어떠한 상황에서 Activity가 상태변이를 일으키는지 눈으로 직접 확인하기 위해 예제를 작성했지만, Activity의 강제 종료를 시뮬레이션 하기 위해서는 실제 메모리가 부족한 상황을 만들어야 하는데 이 부분은 추후 업데이트를 할 예정이다.

 

예제는 2개의 버튼을 가지고 있는 Main Activity 한 개와 sub Activity 2개로 이루어졌다.

Sub Activity중 하나는 Pause 상태를 재현하기 위한 반투명 배경의 Activity이며 (Pause 상태의 조건은 running 중인 activity가 반투명 Activity난 non-full screen Activity에 의해 일부가 가렸을 때 임을 상기), 두 번째 Activity는 Main Activity 의 Stop상태를 재현하기 위한 full screen창이다.

 

상태변이를 확인하기 위해서는 life cycle관련 callback이 호출될 때 마다 Logcat에 Log를 남기는 방법을 사용했다.

(Logcat 사용 방법은 링크 참조)

 

 

Running 상태 재현

 

Activity의 생성시를 보면 다음과 같은 callback들이 호출되는 것을 볼 수 있다.

 

Logcat Log 내용

 

 

 

Running 상태 -> Pause상태 -> Running 상태 재현

 

Running상태인 Main Activity를 Pause상태로 전환 시키기 위해 반투명 sub activity를 foreground로 불러오면 다음과 같은 순서로 callback들이 호출된다.

 

Logcat Log내용

 

눈 여겨 볼만한 점은 onSaveInstanceState(Bundle)의 호출이다. Pause상태의 main activity는 언제 강제 종료 당할지 모르기 때문에 onSaveInstanceState(Bundle)이 call 되고 있다.

 

 

다시 Main Activity로 돌아오기 위해 반투명 sub Activity를 종료하면 (finish() 호출) 다음과 같은 callback이 차례로 호출된다.

 

Logcat Log내용

 

Sub Activity를 우선 종료 후 Main Activity를 foreground로 되돌리는 것이 아니라 Sub Activity를 Pause상태로 만들고 Main Activity가 Sub Activity를 가리면 Sub Activity가 Stop상태로 전환 되고 소멸 된다.

 

 

 

Running 상태 -> Stop상태 -> Running 상태 재현

 

Running 상태인 Main Activity를 Stop상태로 전환 시키기 위해 full-screen size의 Activity를 main activity 앞으로 불러온다.

 

Logcat Log 내용

 

여기서도 Main Activity가 Pause상태에 들어가고 Sub Activity가 foreground를 점유하면서 Main Activity를 완전히 가리면 Main Activity가 Stop() 상태로 전환되는 것을 볼 수 있다.

 

 

Full screen sub Activity를 닫으면 (Activity.finish() 메소드 호출) main activity가 running 상태로 복귀 하는 것을 볼 수 있다.

 

Logcat Log 내용

 

Stop상태였던 Main Activity가 Running 상태로 전환되면서 onRestart()가 호출되는 것을 볼 수 있다.

또, Sub Activity는 Activity.finish() 메소드를 사용해 정상적으로 종료되는 상황이라 onPause()호출 전에 onSaveInstanceState(Bundle) 메소드가 생략된 것도 볼 수 있다.

 

저작자 표시
Posted by 훈남, 밍공™

댓글을 달아 주세요

오늘은 안드로이드 개발에 있어서 없어서는 안될 데이터베이스의 사용법에 대해 알아보겠습니다.

안드로이드는 모바일 환경에 알맞은 SQLite 데이터베이스를 채택하고 있습니다. 기본의 다른 데이터베이스와의 큰 차이는 없습니다.

다른 점이라면, 일반적은 데이터베이스는 테이블 생성시 각 속성에 대한 타입을 지정합니다. 하지만 SQLite는 타입을 지정하는 것이 없습니다. 즉, int, string, text 등의 타입을 지정할 수가 없다는 말이죠. 그러나 메모리와 속도면에서 소규모의 데이터베이스를 운영하는 데 있어서는 이점이 있습니다.

데이터베이스의 사용법은 기존의 데이터베이스를 한번이라도 다뤄보신적 있으신 분은 별 어려움 없이 사용하실 수 있을 것입니다. 처음 접하는 사람들 역시, 기존에 있는 샘플코드를 이용하여 조금만 수정해서 사용하시면, 별 어려움 없이 프로그램에 적용시키실 수 있을 겁니다.

샘플 코드는 인터넷에 널리 퍼져 있는 코드를 정리한 것입니다. 간단한 노트 기능으로 타이틀과 바디를 가지는 테이블이 있고, 이를 이용하여 데이터를 추가, 삭제, 업데이트 등을 수행할 수 있습니다.

   

   

STEP 1  Java Source Code

 

  자바 코드는 크게 두가지로 나뉘어집니다. 데이터베이스를 컨트롤 하는 객체와 이 객체를 사용하여 데이터베이스를 접근하는 엑티비티입니다.

  아래의 예제는 데이터베이스를 컨트롤 하는객체(NotesDbAdapter) 입니다. 이 클래스 내부에 DatabaseHelper객체가 있어 데이터베이스를 관리합니다. 이는 안드로이드에서 제공하는 SQLiteOpenHelper를 상속받아 간단히 만들 수 있습니다. DatabaseHelper 객체에는 크게 세 가지 함수가 존재합니다. 생성자, onCreate, onUpdate 가 있습니다. 말 그대로 onCreate는 데이터베이스를 생성하면서, 데이터베이스 이름과 버전을 설정할 수 있습니다. 이 부분에 쿼리문을 이용하여 데이터베이스의 테이블을 생성합니다. onUpdate는 말 그대로 업데이트가 필요할 시 수행이 됩니다. 현재의 데이터베이스 버전과 업데이트 하려는 데이터베이스의 버전을 비교하여, 낮은 버전일 경우 새롭게 테이블을 구성한다던가, 다른 조작 등을 취할 수 있습니다.

   

[Activity]   데이터베이스 관리 클래스

 

import android.content.ContentValues;

import android.content.Context;

import android.database.Cursor;

import android.database.SQLException;

import android.database.sqlite.SQLiteDatabase;

import android.database.sqlite.SQLiteOpenHelper;

import android.util.Log;

   

   

public class NotesDbAdapter {

   

    public static final String KEY_TITLE = "title";

    public static final String KEY_BODY = "body";

    public static final String KEY_ROWID = "_id";

   

    private static final String TAG = "NotesDbAdapter";

    private DatabaseHelper mDbHelper;

    private SQLiteDatabase mDb;

   

    /**

     * Database creation sql statement

     */

    private static final String DATABASE_CREATE =

"create table notes (_id integer primary key autoincrement, "

            + "title text not null, body text not null);";

   

    private static final String DATABASE_NAME = "data";

    private static final String DATABASE_TABLE = "notes";

    private static final int DATABASE_VERSION = 2;

   

    private final Context mCtx;

   

    private static class DatabaseHelper extends SQLiteOpenHelper {

   

        DatabaseHelper(Context context) {

            super(context, DATABASE_NAME, null, DATABASE_VERSION);

        }

   

        @Override

        public void onCreate(SQLiteDatabase db) {

   

            db.execSQL(DATABASE_CREATE);

        }

   

        @Override

        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {

            Log.w(TAG, "Upgrading database from version " + oldVersion + " to "

                    + newVersion + ", which will destroy all old data");

            db.execSQL("DROP TABLE IF EXISTS notes");

            onCreate(db);

        }

    }

   

    public NotesDbAdapter(Context ctx) {

        this.mCtx = ctx;

    }

   

    public NotesDbAdapter open() throws SQLException {

        mDbHelper = new DatabaseHelper(mCtx);

        mDb = mDbHelper.getWritableDatabase();

        return this;

    }

   

    public void close() {

        mDbHelper.close();

    }

   

    public long createNote(String title, String body) {

        ContentValues initialValues = new ContentValues();

        initialValues.put(KEY_TITLE, title);

        initialValues.put(KEY_BODY, body);

   

        return mDb.insert(DATABASE_TABLE, null, initialValues);

    }

   

    public boolean deleteNote(long rowId) {

   

        Log.i("Delete called", "value__" + rowId);

        return mDb.delete(DATABASE_TABLE, KEY_ROWID + "=" + rowId, null) > 0;

    }

   

    public Cursor fetchAllNotes() {

   

        return mDb.query(DATABASE_TABLE, new String[] { KEY_ROWID, KEY_TITLE,

                KEY_BODY }, null, null, null, null, null);

    }

   

    public Cursor fetchNote(long rowId) throws SQLException {

   

        Cursor mCursor =

   

        mDb.query(true, DATABASE_TABLE, new String[] { KEY_ROWID, KEY_TITLE,

                KEY_BODY }, KEY_ROWID + "=" + rowId, null, null, null, null,

                null);

        if (mCursor != null) {

            mCursor.moveToFirst();

        }

        return mCursor;

   

    }

   

    public boolean updateNote(long rowId, String title, String body) {

        ContentValues args = new ContentValues();

        args.put(KEY_TITLE, title);

        args.put(KEY_BODY, body);

   

        return mDb.update(DATABASE_TABLE, args, KEY_ROWID + "=" + rowId, null) > 0;

    }

}

   

  그 밖에는 함수명에서도 볼 수 있듯이 데이터를 추가, 삭제, 업데이트하는 기능입니다. 기존의 데이터베이스와 다른 점은 쿼리문을 이용하지 않고 데이터를 조정이 가능한 것입니다. ContentValues 라는 타입을 이용하여 기존에 있는 테이블의 속성명과 조작하려는 인스턴스를 넣어 한꺼번에 데이터베이스로 요청할 수 있습니다. Insert, update 같이 데이터베이스 객체 내에 있는 함수를 이용하여 쿼리문 없이 데이터베이스 조작이 가능합니다. 이러한 함수는 내부에서 직접 쿼리문을 만들어 데이터베이스로 쿼리문을 날립니다.

자신이 사용하고 싶은 테이블을 구성하신 뒤에, 이 코드를 자신에 맞는 테이블로 바꾸시면 큰 어려움 없이 데이터베이스를 이용하실 수 있으실 겁니다.

 

[Bouns]   Cursor 사용

 

moveToFirst

커서가 쿼리(질의) 결과 레코드들 중에서 가장 처음에 위치한 레코드를 가리키도록 합니다.

moveToNext

다음 레코드로 커서를 이동합니다.

moveToPrevious

이전 레코드로 커서를 이동합니다.

getCount

질의 결과값(레코드)의 갯수를 반환합니다.

getColumnIndexOrThrow

특정 필드의 인덱스값을 반환하며, 필드가 존재하지 않을경우 예외를 발생시킵니다

getColumnName

특정 인덱스값에 해당하는 필드 이름을 반환합니다.

getColumnNames

필드 이름들을 String 배열 형태로 반환합니다.

moveToPosition

커서를 특정 레코드로 이동시킵니다.

getPosition

커서가 현재 가리키고 있는 위치를 반환합니다.

 

  데이터베이스의 특성상 하나의 테이블의 레코드를 읽어 오기 위해서는 커서라는 것이 필요합니다. 조건에 맞는 레코드를 한꺼번에 모두 들고 올 수가 없기 때문에 커서를 이용해서 조작을 합니다. 말 그대로 커서는 현재 레코드를 가리키고 있는 곳을 말합니다. 하나씩 이 커서를 이동하면서 레코드 하나하나씩을 접근해서 가져옵니다. 이 커서 객체를 이용하여 get을 하게 되면 컬럼 번호에 맞게 데이터를 가져올 수 있습니다.

 

[Activity]   데이터베이스 이용 엑티비티

 

import android.app.Activity;

import android.database.Cursor;

import android.os.Bundle;

import android.util.Log;

import android.view.View;

import android.widget.Button;

import android.widget.TextView;

   

public class DatabaseTestActivity extends Activity {

   

    private NotesDbAdapter dbAdapter;

    private static final String TAG = "NotesDbAdapter";

   

        

@Override

    public void onCreate(Bundle savedInstanceState) {

    super.onCreate(savedInstanceState);

    setContentView(R.layout.main);

   

    Log.d(TAG, "DatabaseTest :: onCreate()");

   

    dbAdapter = new NotesDbAdapter(this);

    dbAdapter.open();

   

     Button bt = (Button)findViewById(R.id.inputButton);

     bt.setOnClickListener(new View.OnClickListener() {

   

            public void onClick(View v) {

                dbAdapter.createNote("title", "body");

                TextView tv = (TextView)findViewById(R.id.textView1);

                tv.setText("데이터베이스에 넣었습니다.");

                TextView tv1 = (TextView)findViewById(R.id.textView2);

                tv1.setText("Title Body 데이터베이스에 저장하였습니다.");

                 Log.d(TAG, "First Button Click");

            }

        });

   

        Button bt1 = (Button)findViewById(R.id.outputButton);

        bt1.setOnClickListener(new View.OnClickListener() {

   

            public void onClick(View v) {

                Cursor result =    dbAdapter.fetchAllNotes();

                result.moveToFirst();

   

                while(!result.isAfterLast()){

                  String title = result.getString(1);

                  String body = result.getString(2);

   

                  TextView tv = (TextView)findViewById(R.id.textView1);

                  tv.setText(title);

                  TextView tv1 = (TextView)findViewById(R.id.textView2);

                  tv1.setText(body);

                  result.moveToNext();

   

                }

                Log.d(TAG, "Second Button Click");

                result.close();

            }

        });

 }

}

   

  위의 코드는 실제 엑티비티에서 데이터베이스를 이용하는 것을 나타내는 소스코드입니다. 위에서 살펴본 NotesDbAdapter 객체를 생성하여, open()을 한 뒤 사용하면 됩니다. 사용하는 법은 너무나도 직관적이라 생략하겠습니다. While문을 이용하여 커서를 이용하여 테이블에 있는 모든 레코드를 가져와서 화면에 뿌려주는 것을 수행하는 코드입니다.  

   

STEP 2  Xml Code

   

  Xml코드에는 간단히 테스트할 수 있는 TextView객체 두 개만 생성하고 있습니다.  

   

STEP 3  AndroidManifest.xml Code

 

  데이터베이스를 이용하기 위해서 AndroidManifest.xml 코드 수정은 필요하지 않습니다.

   

 

 

 < 마무리 >  SQLite 데이터베이스 사용하기

 

  데이터베이스를 사용하기 위해서는 안드로이드에서 제공하는 SQLiteOpenHelper를 이용하여 간단히 데이터베이스를 조작할 수 있습니다. 이 것을 상속받아 객체를 만들고 이 객체를 자신의 데이터베이스에 맞게 조작하도록 클래스(NotesDbAdapter)를 만들고, 엑티비티에서는 이 클래스를 생성하여 데이터베이스를 직접 사용할 수 있게 합니다. 간단한 샘플 코드를 이용하여 자신의 데이터베이스 테이블에 맞게 수정하여 사용하면 간단히 데이터를 저장할 수 있는 환경이 됩니다.

 

<출처:http://pulsebeat.tistory.com/15>

저작자 표시
Posted by 훈남, 밍공™

댓글을 달아 주세요

AndroidManifest.xml

Android / 2010/06/24 12:01



<?xml version=”1.0” encoding=”utf-8”?>

<manifest>

<uses-permission />

<permission />

<permission-tree />

<permission-group />

<instrumentation />

<uses-sdk />

<uses-configuration />

<uses-feature />

<supports-screens />

<application>

<activity>

<intent-filter>

<action />

<category />

<data />

</intent-filter>

<meta-data />

</activity>

<activity-alias>

<intent-filter> . . . </intent-filter>

<meta-data />

</activity-alias>

<service>

<intent-filter> . . . </intent-filter>

<meta-data/>

</service>

<receiver>

<intent-filter> . . . </intent-filter>

<meta-data />

</receiver>

<provider>

<grant-uri-permission />

<path-permission />

<meta-data />

</provider>

<uses-library />

</application>

</manifest>


매니패스트 파일은 어플리케이션에 대한 전반적인 정보를 담고 있는 파일로, 어플리케이션이 실행되기 전에 시스템이 알고 있어야 하는 파일이다. 이 매니페스트 파일 안에는 어플리케이션 컴포넌트(Activity, Service, intents, Content provider, Broadcast Receivers)에 대한 노드를 포함하고 있고 Intent filter와 같이 permissions을 사용해 다른 컴포넌트와 어플리케이션이 어떻게 상호 작용을 하는지를 결정한다.


</receiver>

<provider>

<grant-uri-permission />

<path-permission />

<meta-data />

</provider>

<uses-library />

</application>

</manifest>

<manifest>

<manifest xmlns:android="http://schemas.android.com/apk/res/android"

    package="com.example.android.notepad"

android:versionCode="1"

    android:versionName="1.0">

[어플리케이션 태그 Permission 태그들]

</manifest>

AndroidManifest.xml의 root element로써 <manifest> 태그가 전체를 감싸는 구조를 하고 있으며 package attribute의 값으로는 어플리케이션의 base를 지정하는 Java package 이름이 온다.

 

<uses-permission>

<uses-permission android:name="string" />

어플리케이션의 필요한 기능의 권한을 정의해준다. 여기에 정의된 권한은 설치 과정 중 사용자에게 보여주고 권한부여 혹은 거절이 결정된다.

android:name 애플리케이션 안에 <permission>엘리먼트를 사용해서 정의된 퍼미션 이름

다른 애플리케이션에 의해 정의된 퍼미션의 이름

표준 시스템 퍼미션의 이름( - android.permission.INTERNET)


<permission>

<permission android:description="string resource"

android:icon="drawable resource"

android:label="string resource"

android:name="string"

android:permissionGroup="string"

android:protectionLevel=["normal" | "dangerous" | "signature" | "signatureOrSystem"]

/>

컴포넌 사용하기 위한 권한 중에 안드로이드가 제공하는 권한 이외에 다른 권한이 필요할 때 정의한다. 다른 어플리케이션이 이 컴포넌트를 사용하려면 자신의 매니페스트에 uses-permission 태그를 설정해 주거나<activity android:permission>속성에 권한을 추가해 주면 된다.

                                android:description 퍼미션의 설명으로 사용자에게 퍼미션을 설명하기 위해 사용 될 수도 있다.

android:icon 퍼미션을 의미하는 아이콘의 리소스의 레퍼런스로 예를 들어 res/drawable/app_note.png라는 파일이 있다면 @drawable/app_note라고 쓴다.

android:label 사용자에게 보여질 수 있는 퍼미션의 이름다. 배포가 될때는 string.xml에 정의하고 @string/app_name 같이 사용하여야 한다.

android:name 코드에서 사용되는 퍼미션의 이름이다. com.example.project.PERMITTED_ACTION과 같이 고유한 이름을 사용해야 한다.

android:permissionGroup 그룹에 퍼미션을 할당한다. <permission-group>으로 선언되어진 그룹의 이름을 지정한다.

android:protectionLevel 이 레벨 설정에 따라서 사용자가 퍼미션을 요구하는 애플리케이션을 알 수 있거나 해당 퍼미션을 누가 사용하는지를 알 수 있다.

normal : 디폴트 값으로 낮은 수위의 위험을 갖는다. 최소한의 위험요소를 가진 애플리케이션이 다른 애플리케이션 레벨의 기능들에 대해 접접근하는 것 부여한다.

dangerous : 높은 수위의 위험을 갖는다. 사용자의 사적 데이터 접근이나 디바이스에 대한 제어를 허용한다.

signature : 애플리케이션이 다른 애플리케이션과 같은 인증서를 가지고 사인되었을때에 한하여 시스템이 퍼미션을 부여한다.

signatureOrSystem : 시스템이 안드로이드 시스템 이미지 안에 있거나 시스템 이미지 안에 있는 것들과 같은 인증서로 사인된 애플리케이션에 한하여 부여한다.


<permission-tree>

<permission-tree android:icon="drawable resource"

   android:label="string resource"

      android:name="string" />

퍼미션 트리에 대한 기본적인 이름을 선언한다. 이 애플리케이션은 트리 내의 모든 이름들에 대한 소유권을 갖는다.


<permission-group>

<permission-group android:description="string resource"

 android:icon="drawable resource"

 android:label="string resource"

        android:name="string" />

퍼미션 그룹의 이름을 선언한다.


<instrumentation>

실행 시 액티비티와 서비스를 테스트 하기 위한 프레임워크롤 제공하며, 선언된 클래스는 시스템리소스와 상호작용을 모니터링하기 위한 연결 고리를 제공한다.

Jfeature를 설치해 Test를 사용할 경우

<instrumentation android:targetPackage="com.jfeature" android:name="android.test.InstrumentationTestRunner" />

<instrumentation android:functionalTest=["true" | "false"]

android:handleProfiling=["true" | "false"]

android:icon="drawable resource"

android:label="string resource"

android:name="string"

android:targetPackage="string" />

이 엘리먼트가 매니페스트에 자동으로 생성된다.

android:functionalTest 기능적 테스트를 위해 수행되어야 하는지 여부를 표시한다. 디폴트 값은 false이다.

android:handleProfiling 프로파일링을 on, off 할 것인지의 여부를 표시한다. 프로파일링을 시작할 때와 멈출때는 결정하려면 ture, 프로파일링이 시행되는 모든 시간 동안 계속 하려면 false로 표시한다. 디폴트는 false이다.

android:targetPackage 타겟으로 정할 패키지 주소를 입력한다.


<uses-sdk>

<uses-sdk android:minSdkVersion="integer"

android:maxSdkVersion="integer"

amdroid:targetSdkVersion="integer" />

Android Version이 아닌 API 레벨을 설정한다.

android:minSdkVersion API의 최소레벨을 지정하는 함수로 Default값은 1이다.

시스템이 지정한 값보다 낮은 버전 이라면 시스템에 설치 되지 않는다.

android:maxSdkVersion API의 최소레벨을 지정하는 함수이다. 시스템이 지정한 값보다 높은 버전이라면 시스템에 설치 되지 않는다. 이 애트리뷰트를 사용하는 것을 권장하지 않는다. 왜냐하면 신규 버전의 안드로이드 플렛폼 배치가 차단되고 더 높은 API 레벨로 시스템이 업데이트 된 이후 사용자의 디바이스에서 maxSdkVersion이 시스템보다 낮은 값으로 설정된 애플리케이션이 제거된다.

android:targetSdkVersion - 애플리케이션이 타겟으로 하고 있는 API 레벨을 지정하는 함수이다.


<uses-feature>

<uses-feature android:glEsVersion="integer"

       android:name="string" />

SDK버전을 선언하는 것과 비슷하게 기능을 지원하지 않는 디바이스 상에는 설치가 되지 않도록 하는 옵션이다. 예를 들어 디바이스가 카메라를 지원하지 않으면 어플리케이션이 설치 되지 않는다. 애플리케이션이 특정 디바이스를 사용해야 한다면 이 옵션을 추가해야 한다.

                                   android:glEsVersion 애플리케이션이 필요로 하는 GLES 버전이다.

android:name 애플리케이션이 필요로 하는 기능의 이름으로써 예로 android.hardware.camera와 같이 쓰이는데 이것은 애플리케이션이 카메라를 필요로 한다는 의미이다.

<supports-screens>

<supports-screens android:smallScreens=["true" | "false"]

                 android:normalScreens=["true" | "false"]

                 android:largeScreens=["true" | "false"]

                 android:anyDensity=["true" | "false"] />

애플리케이션이 지원하는 스크린 크기를 지정하는 옵션이다.(멀티해상도 관련)

android:smallScreens 애플리케이션이 normal보다 더 작은 스크린을 지원하는지 여부이다. API 레벨 4이상에서는 디폴트 값이 ture이고 다른 레벨에서는 false이다.

android:normalScreens 애플리케이션이 normal 스크린을 지원하는지 여부다. 디폴트 값은 true이다.

android:largeScreens 애플리케이션이 normal보다 더 큰 스크린을 지원하는지 여부이다. API 레벨 4이상에서는 디폴트 값이 ture이고 다른 레벨에서는 false이다.

android:anyDensity 애플리케이션이 임의의 스크린 밀도를 수용할 수 있는 지에 대한 옵션이다. API레벨 4이상에서는 디폴트 값이 true이고 다른 레벨에서는 false이다.


<application>

<application android:allowClearUserData=["true" | "false]

android:allowTaskReparenting=["true" | "false"]

android:debuggable=["true" | "false"]

android:description="string resource"

android:enabled=["true" | "false"]

android:hasCode=["true" | "false"]

android:icon="drawable resource"

android:label="string resource"

android:manageSpaceActivity="string"

android:name="string"

android:permission="string"

android:persistent=["true" | "false"]

android:process="string"

android:task="string"

android:theme="resource or theme" >

. . .

</application>

이 엘리먼트는 반드시 한번 사용되어야 한다. Application 아래에 있는 서브 엘리먼트는 없거나 순서가 바뀌어도 문제되지 않는다. 애플리케이션의 메타데이타(타이틀, 아이콘, 테마 등)을 지정한다.

                                    android:allowClearUserData 사용자들에게 사용자 데이터를 제거할 수 있는 옵션을 부여할 것인가에 대한 애트리뷰트이다.

                                    android:allowTaskReparenting 이 애트리뷰트가 true로 설정되어 있다면 액티비티는 시작된 태스크부터 affinity를 갖는 태스크가 된다.

예를 들어 e-mail Activity에서 web page링크를 클릭하게 되면 해당 페이지가 보여지는 브라우저가 시작되게 된다. 이 Activity는 Browser Application에 정의 되어 있지만 e-mail Task의 일부로 실행된 상태이다. 만약 android:allowTaskReparenting이 true로 되어있고 Browser Task로 Reparenting되면 Browser어플리케이션에서 그 페이지가 보여질 것이고 다시 e-mail Task가 보여지면 그 Activity는 보이지 않게 된다. 디폴트 값은 false이다.

D:\WORK\리소스\Task.png

                                 android:debuggable 사용자모드로 실행중일 때 디버그 될수 있는지를 설정한다. 디폴트 값은 false이다. false로 설정한다면 Wating for Debugger화면에서 더 이상 진행되지 않는다.

     android:enable 애플리케이션의 컴포넌트를 인스턴스화 할 수 있는지를 설정한다. 디폴트 값은 true이다. “true”라면 각 컴포넌트의 enabled 애트리뷰트가 그 컴포넌트의 활성화 여부를 결정하고 false라면 모든 컴포넌트들은 비활성화 된다.

 android:hasCode 시스템 코드가 아닌 다른 코드를 포함하고 있는지를 설정한다. 디폴트 값은 true이다.

 android:manageSpaceActivity 디바이스상에서 애플리케이션이 점유하는 메모리를 사용자가 관리 할 수 있도록 하는 액티비티 이름이다.

adroid:permission 클라이언트와 애플리케이션이 상호작용하기 위해 필요한 퍼미션 이름이다. 이 애트리뷰트는 애플리케이션 안의 모든 컴포넌트에 퍼미션을 적용한다.

android:persistent 애플리케이션이 항상 실행 상태로 있는지의 설정값이다. 디폴트는 false이다.

android:process 애플리케이션 프로세스의 이름이다. 애플리케이션 안에 모든 컴포넌트는 이 애트리뷰트의 프로세스로 실행이 되고 각 컴포넌트에 process 애트리뷰트를 설정 함으로써 오버라이드 할 수 있다. 디폴트 <manifest>엘리먼트의 package이름이다. 이 애트리뷰트의 이름이 콜론(:)으로 시작되면 private하고 소문자로 시작한다면 그 이름을 가진 글로벌 프로세스가 만들어진다. 글로벌 프로세스는 공유될 수 있어 리소스 사용을 감소시킨다.

android:taskAffinity 애플리케이션 안 모든 액티비티에 적용되는 affinity이름이다. 액티비티 내에 taskAffinity를 설정했다면 적용되지 않는다. 디폴트로 <manifest>엘리먼트의 package 이름을 가지고 어플리케이션내에 액티비티는 동일 Affinity를 공유한다.

android:theme 애플리케이션 안의 모든 액티비티에 적용되는 스타일 리소스에 대한 레퍼런스 이다. 각각의 액티비티는 이 설정을 override 할 수 있다.


<activity>

<activity android:allowTaskReparenting=["true" | "false"]

android:alwaysRetainTaskState=["true" | "false"]

android:clearTaskOnLaunch=["true" | "false"]

android:configChanges=[one or more of: "mcc" "mnc" "locale"

"touchscreen" "keyboard" "keyboardHidden" "navigation" "orientation" "fontScale"]

android:enabled=["true" | "false"]

android:excludeFromRecents=["true" | "false"]

android:exported=["true" | "false"]

android:finishOnTaskLaunch=["true" | "false"]

android:icon="drawable resource"

android:label="string resource"

android:launchMode=["multiple" | "singleTop" | "singleTask" | "singleInstance"]

android:multiprocess=["true" | "false"]

android:name="string"

android:permission="string"

android:process="string"

android:screenOrientation=["unspecified" | "user" | "behind" | "landscape" | "portrait" | "sensor" | "nonsensor"]

android:stateNotNeeded=["true" | "false"]

android:taskAffinity="string"

android:theme="resource or theme"

android:windowSoftInputMode=[one or more of: "stateUnspecified"

"stateUnchanged" "stateHidden"

"stateAlwaysHidden" "stateVisible"

"stateAlwaysVisible" "adjustUnspecified"

"adjustResize" "adjustPan"] >

. . .

</activity>

각각의 액티비티마다 <activity>태그가 필요하다. 매니페스트 파일에 액티비티가 정의되어 있지 않다면 해당 액티비티를 실행시킬 수 없다.(런타임 오류가 발생)

                        android:allowTaskReparenting 친화력 있는 태스크 설정 애트리뷰트이다. 이 애트리뷰트가 설정되지 않으면 <application>엘리먼트의 allowTaskReparenting에 설정된 값이 액티비티에 적용된다. 디폴트 값은 false이다.

                        android:alwaysRetainTaskState 사용자가 Task를 오랫동안 방치하면 시스템은 Root Activity를 제외한 모든 Activities의 Task를 Clear 시킨다. 이 애트리뷰트가 true로 설정 되어 있다면 Task는 오랜 시간이 지나도 Stack에 있는 모든 Activity를 유지한다. 디폴트 값은 false이다.

                        android:clearTaskOnLaunch 이 속성이 true로 설정되어 있으면 사용자가 Task를 떠났다가 다시 돌아 올 때마다 Stack은 Root Activity로 정리된다. 디폴트 값은 false이다.

                        Android:configChanges 시스템은 각 어플리케이션을 종료하고 재시작한 뒤 리소스 값을 다시 읽어 들임으로써 언어, 위치, 하드웨어에 대한 런타임 변경을 지원한다. 런타임 구성 변경을 감지하는 activity를 가지려면 Manifest 노드에 android: configChanges 속성을 추가 한 뒤 변경을 하고자 하는 구성 변경을 지정한다. 여러 값을 사용할 때는 |’에 의해 구분된다.

mcc : IMSI 모바일 국가 코드가 변경되었다.

mnc : IMSI 모바일 네트워크 코드가 변경되었다.

locale : 사용자가 다른 언어 설정을 선택했다.

touchscreen : 터치스크린이 변경되었다.

keyboard : 키보드 종류가 바뀌었다.

keyboardHidden : 키보드가 보여졌거나 숨겨졌다.

navigation : 네비게이션 타입이 변경 되었다.

origentation : 화면이 세로 방향이나 가로 방향으로 회전됐다.

fontScale : 사용자가 선호하는 글꼴 크기를 변경했다.


/// Configuraion 객체를 사용해 새로운 구성 값을 결정하도록

/// OnConfigurationChnaged 메서드를 한다.

@Override

public void onConfigurationChanged(Configuration _newConfig) {

      super.onConfigurationChanged(_newConfig);

     // resource 값에 기반을 두고 있는 모든 GUI update 한다.


     // ....

     if (_newConfig.orientation == Configuration.OPRIENTATION_LANDSCAPE)

{

        // 방향이 landscape 변경되면 해당 방향으로 반응을 한다.

}


    if (_newConfig.keyboardHidden == Configuration.KEYBOARDHIDDEN_NO)

    {

        // 변경된 키보드의 유무에 반응을 한다.

    }

}

시스템이 재시작 되지 않을 경우 다음과 같이한다.

android:excludeFromRecents true이면 사용자가 볼 수 있는 최근 런치된 액티비티 리스트에서 제외되고 false이면 리스트에 포함된다. 디폴트 값은 false이다.

android:exported 다른 애플리케이션의 컴포넌트에서 이 액티비티를 런치 할 수 있는지를 설정한다. false”라면 이 액티비티는 같은 애플리케이션 혹은 같은 유저 ID를 가진 애플리케이션 컴포넌트만 런치 할 수 있다. 디폴트는 액티비티가 인텐트 필터를 포함하는지에 달려있다. 필터가 없다면 디폴트 값이 false이고 필터가 있다면 true이다.

MAIN/LAUNCHER 액티비티에는 절대로 false값을 주면 안 된다. false값을 주게 되면 SecurityException이 발생하고 exported 속성을 true로 설정해 달라는 메시지가 출된다.

            android:finishOnTaskLaunch 사용자가 태스크를 런치 할 때 마다 액티비티의 기존 인스턴스가 종료 되어야 하는지의 여부를 설정한다. 종료되어야 한다면 true이고 종료되지 않아야 한다면 false이다. 디폴트 값은 false이다. 만약 이 애트리뷰트와 allowTaskReparenting이 모두 true라면 액티비티 친화력은 무시되어 액티비티는 부모를 바꾸지 않고 파괴된다.

android:launchMode 액티비티가 어떻게 런치되어야 하는지에 대한 명령이다. 4가지 런치모드(standard singleTop” “singleTask singleInstance )가 있고 디폴트는 standard이다.

모드는 두개의 main Group으로 나뉜다(standard, singleTop / singleTask, singleInstance). standard, singleTop모드를 가지는 액티비티는 여러 번 인스턴스화 될 수 있으나(Intent Object가 FLAG_ACTIVITY_NEW_TASK flag를 가지고 있지 않을 경우에 해당) singleInstance 액티비티는 하나의 Task만 시작 할 수 있다.

standard vs singleTop : standard 액티비티에 대한 새로운 Intent가 발생하면 언제나 해당 Class의 Instance가 만들어 지지만 singleTop 액티비티의 새로운 Instance는 생성 될 수도 있다. 즉, Target Task에 이미 해당 액티비티의 인스턴스가 존재하면 새로 만들어지지 않고 기존 인스턴스가 새로운 Intent를 받게 된다.

singleTask vs singleInstance : singleTask 액티비티는 다른 액티비티들이 해당 Task의 일부가 되는 것을 허락하여 singleTask 액티비티는 액티비티 스택의 root에 존재하게 되고 다른 액티비티들은 동일한 Task에서 시작 될 수 있다. 이와 달리 singleInstance 액티비티는 어떤 다른 액티비티들도 해당 Task의 일부가 될 수 없다. 이로 인해 해당 Task에는 유일한 Activity만 존재하고 또 다른 Activity를 실행하려고 하면 새로운 Task로 할당이 된다.

android:multiprocess 이 플래그가 true이면 액티비티 인스턴스가 다양한 프로세스에서 실행 될 수 있다. 디폴트 값은 false이고 true값은 지양한다.

android:noHistory true라면 사용자가 액티비티를 떠나 화면에 보이지 않았을 때 스택에서 제거되고 종료(finish()메소드가 호출됨)된다. 기본값은 false이다.

android:permission 액티비티를 런치하기 위해 혹은 인텐트에 응답하기 위해 얻어야 하는 퍼미션 이름이다. 만약 startActivity() 또는 startActivityForResult()의 호출자가 퍼미션을 부여받지 않으면 인텐트는 해당 액티비티에 전달 되지 않는다.

애트리뷰트가 설정되지 않으면 <application>엘리먼트의 퍼미션이 적용되고 <application>엘리먼트 퍼미션이 없다면 이 액티비티는 퍼미션에 의해 보호되지 않는다.

android:process 액티비티가 실행되어야 하는 프로세스의 이름이다. 디폴트 프로세스 이름은 어플리케이션 패키지 이름이다.

android:screenOrientation 액티비티의 방향을 설정한다.

unspecified : 시스템에서 디바이스에 따라 방향을 결정

landscape : 가로방향

portrait : 세로방향

behind : 이전 액티비티의 스택에 따라 결정

user : 사용자 설정

sensor : 가속 센서의 방향에 따라 결정

nosensor : 가속 센서를 사용하지 않음, unspecified와 비슷

android:stateNotNeeded 액티비티가 임시로 종료되기 전에 리소스를 저장하기 위해 onSaveInstanceState() 메쏘드가 호출된다. 메쏘드는 액티비티가 재시작될 , onCreate() 전달되는 Bundle 액티비티의 현재 상태를 저장한다. 만약 애트리뷰트가 true”로 설정되 onSaveInstanceState() 호출되지 onCreate() bundle 대신에 null 전달받는다. 디폴트 값은 false이다.

android:taskAffinity 이곳에 다른 task name을 설정해 주면 이 액티비티는 해당 task에 실행된다. 하나의 어플리케이션에서 실행되는 아이콘을 여러 개 만드는데 사용된다. 기본적으로 액티비티는 애플리케이션의 친화력을 상속한다. 애플리케이션의 디폴트 친화력 이름은 <manifest>엘리먼트의 패키지 이름이다.

android:theme 액티비티의 테마를 정의하는 스타일 리소스에 대한 레퍼런스이다. 기본적으로 <application>엘리먼트의 테마를 사용하고 테마가 없으면 시스템 테마가 사용된다.

android:windowSoftInputMode 소프트 키보드 상태 : 액티비티가 사용자 관심의 포커스를 받을 때 소프트 키보드가 보여지는지 여부를 설정한다.

액티비티 메인 윈도우에 대한 조정 : 소프트 키보드를 위한 공간을 만들기 위해 액티비티 메인 윈도우를 작게 줄일 지의 여부 또는 메인 윈도우 일부가 소프트 키보드에 의해 가려질 때 현재 포커스를 보이도록 하기 위해 메인 윈도우의 컨텐트가 상하로 움직일 지의 여부를 설정한다.

stateUnspecified : 소프트 키보드 상태에 대해 시스템이 적절한상태를 선택하거나 테마 설정값을 따른다. 소프트 키보드의 디폴트 설정 값.

stateUnchanged : 소프트 키보드는 마지막 상태로 유지

stateHidden : 사용자 액티비티를 선택할 때 소프트 키보드는 숨겨짐

stateAlwaysHidden : 액티비티의 메인 위도우가 입력 포커스를 가질 때 소프트 키보드는 항상 숨겨짐

stateVisible : 사용자가 액티비티 메인 위도우 앞으로 갈 때 소프트 키보드 보여짐

stateAlwaysVisible : 사용자가 액티비티를 선택할 때 소프트 키보드 보여짐

adjustUnspecified : 스크롤 할 수 잇는 레이아웃 뷰들을 가지고 있다면 윈도우 크기 재조정. 메인 윈도우의 디폴트 값

adjustResize : 스크린에 소프트 키보드 공간을 만들기 위해 메인 윈도우 크기가 항상 재조정 됨

adjustPan : 소프트 키보드 공간을 만들기 위해 메인 윈도우 크기가 재조정 되지 않음


<intent-filter>

수행되어야 할 Action을 서술해 놓은 정보의 묶음이다. 이 정보에는 수행되었을 때의 데이터, Action을 수행하기 위한 구성 요소의 Category, 그리고 또 다른 적절한 지시 등이 포함된다.

Android System은 Component를 구동하기 전에 Component가 다루려 하는 의도를 파악해야 하기 때문에 Intent Filters은 <intent-filter> 요소로 Manifest에 규정되어 있어야 한다. 하나의 Component는 여러 개의 Filters을 가질 수 있고 각각은 서로 다른 Capabilities를 나타내게 된다.

<intent-filter android:icon="drawable resource"

android:label="string resource"

android:priority="integer" >

. . .

</intent-filter>

Target Component를 명시적으로 명명한 Intent는 해당 Component를 활성화 시키게 되는데 이 때는 filter가 사용되지 않는다. 그러나 명시적으로 Target을 정하지 않게 되면 Component's Filters 중 하나를 통해 전달하게 된다.

android:priority 부모 컴포넌트가 필터에 따른 인텐트 처리의 우선순위이다. 액티비티와 브로드캐스드의 경우에 해당한다.

필터와 일치하는 인텐트에 대해 응답 방법에 대한 정보를 제공하고 인텐트에 대한 잠재적 타겟으로 높은 우선순위인 액티비티만을 고려한다.

높은 우선순위의 값을 가지는 브로트캐스트 리시버가 먼저 호출된다.


<action>

<action android:name="string" />

<intent-filter>엘리먼트는 반드시 하나이상의 <action>엘리먼트를 포함해야 한다.

android:name 액선의 이름으로써 ACTION_문자열 상수이다. 예를들어 ACTION_MAIN에 대해서는android.intent.action.MAIN, ACTION_WEB_SEARCH에 대해서는 anroid.intent.action.WEB_SEARCH를 사용한다.

안드로이드 패키지가 아닌 직접 정의한 액션에 대해서는 접두어로 패키지 이름을 사용하는 것이 좋다. 예를들어 TRANSMOGRIFY액션은 com.example.project.TRANSMOGRIFY 처럼 사용한다.

<category>

<category android:name="string" />

인텐트가 카테고리 테스트를 통과하기 위해서는 인텐트 오브젝트 안의 모든 카테고리가 필터에 있는 카테고리와 일치해야 한다.

android:name 카테고리의 이름으로써 CATEGORY_name 상수이다. 예를들어 CATEGORY_LAUNCHER에 대한 문자열 값은 android.intent.category.LAUNCHER이다.

<data>

URI와 데이터 타입(MIME 미디어 타입) 지정 할 수 있다. schema, host, port, path와 같은 URI 애트리뷰트들에 의해 지정된다.

scheme://host:port/path 또는 pathPrefix 또는 pathPattern

예를들어 content://com.example.project:200/folder/subfolder/etc이다.

<data android:scheme=”something” android:host=”project.example.com” />

<data android:host="string"

android:mimeType="string"

android:path="string"

android:pathPattern="string"

android:pathPrefix="string"

android:port="string"

android:scheme="string" />

<data android:scheme=”something” /><data android:host=”project.example.com” /> 동일하다.

android:host URI authority의 host영역이다. scheme가 없으면 이 애트리뷰트는 의미가 없다. 호스트 이름은 항상 소문자로 지정해야 한다.

android:mimType image/jpeg 또는 audio/mpeg4-generic과 같은 MIME 미디어 타입이다. 하위타입에 대해 와일드카드(*)를 사용할수 있으면 항상 소문자를 사용해서 지정해야 한다.

android:path

android:pathPrefix

android:pathPattern URI authority의 path영역이다. path 애트리뷰트는 인텐트 오브젝트 내의 전체 path와 일치하는 path를 지정한다. pathPrefix 애트리뷰트는 인텐트 오브젝트 내 path의 첫 머리만 일치하는 부분적인 path를 지정한다. pathPattern 애트리뷰트는 인텐트 오브젝트 내의 전체 path와 일치하는 path를 지정하지만 다음과 같은 와일드카드를 포함할 수 있다. 첫째로 별표(*)는 바로 앞에 나오는 문자가 0번 이상 발생하는 것을 나타내고 둘째로는 마침표 뒤에 별표가 나오는 것(.*)은 어떤 문자든 0번 이상 발생하는 것을 나타낸다.

XML에서 \은 이스케이프 문자로써 사용된다.

scheme와 host 애트리뷰트가 필터에 없으면 이 애트리뷰트는 의미가 없다.

android:port - URI authority의 port영역이다. scheme와 host 애트리뷰트가 지정될 때에만 의미를 같는다.

android:scheme URI authority의 scheme영역이다. Scheme이 없다면 나머지 애트리뷰트는 의미가 없다. 스키마는 항상 소문자를 사용해야 한다.


<meta-data>

데이터에 대한 정의나 설명이다. 컴포넌트 엘리먼트는 <meta-data> 서브엘리먼트를 포함할 수 있다. <meta-data>의 모든 값은 하나의 Bundle로 모아지고 PackageItemInfo.metaData 필드로써 컴포넌트에서 사용할 수 있다.

<meta-data android:name="string"

android:resource="resource specification"

android:value="string" />

android:name 아이템에 대한 고유한 이름이다. 예를들어 com.example.project.activity.fred처럼 Java 스타일 naming 규약을 사용해야 한다.

android:resource 리소스에 대한 레퍼런스 이다. ID는 Bundle.getInt() 메쏘드에 의해 meta-data Bundle로부터 얻을수 있다.

android:value 아이템에 할당된 값이다. 아래는 값으로 할당 할수 있는 데이터 타입과 값을 얻기 위해 사용하는 메쏘드들이다.

타입

Bundle 메쏘드

유니코드 문자를 위한 \\n \\uxxxxx 같은 스케이프(escape) 캐릭터에 더블 백슬래시(\\) 사용하는 문자열

getString()

100같은 정수(integer)

getInt()

(true) 또는 거짓(false) 하나인 boolean

getBoolean()

#rgb,#argb,#rrggbb 또는 #aarrggbb형식의 컬러

getString()

1.23 같은 부동소수점

getFloat()


<activity-alias>

<activity-alias android:enabled=["true" | "false"]

android:exported=["true" | "false"]

android:icon="drawable resource"

android:label="string resource"

android:name="string"

android:permission="string"

android:targetActivity="string" >

. . .

</activity-alias>

<activity> 타겟으로 지정해 그 타겟과 다른 속성으로 <activity>를 호출한다. targetActivity는 같은 <application>안에 있어야 하고 <activity-alias>보다 먼저 선언 되어 있어야 한다. targetActivity는 Activity-alias의 부모 엘리먼트이고 activity-alias는 targetActivity의 애트리뷰트를 따르지만 activity-alias안에 같은 애트리뷰트가 선언되면 activity-alias 애트리뷰트 값을 따른다.

android:exported 다른 애플리케이션의 컴포넌트들이 이 앨리어스를 통해 타겟 액티비티를 런치할 수 있는지를 설정한다. 런치할 수 있다면 true이다. 인텐트 필터가 없으면 디폴트 값은 false이고 인텐트 필터가 있다면 디폴트 값은 true이다.

android:name 앨리어스의 이름을 지정한다. 이름은 전체 클래스 이름과 비슷해야 하고 실제 클래스 이름을 참조하지 않는다.

android:permission 이것이 설정된다면 targetActivity 퍼미션을 대체한다. 설정이 되지 않는다면 앨리어스를 통해 타겟을 활성화 하기 위한 퍼미션은 필요하지 않다.

android:targetActivity 앨리어스를 통해 활성화 될 수 있는 액티비티의 이름을 지정한다.


<service>

<service android:enabled=["true" | "false"]

android:exported=["true" | "false"]

android:icon="drawable resource"

android:label="string resource"

android:name="string"

android:permission="string"

android:process="string" >

. . .

</service>

각 서비스마다 <service>태그가 필요하다. 서비스는 백그라운드 오퍼레이션이나 다른 애플리케이션이 호출 할 수 있는 커뮤니케이션 API를 구현하기 위해 사용된다.

android:icon 서비스 아이콘은 이곳에서 설정하던 <application>엘리먼트에서 설정하던 모든 서비스의 인텐트 필터에 대한 디폴트 아이콘이다.

android:label 서비스 아이콘은 이곳에서 설정하던 <application>엘리먼트에서 설정하던 모든 서비스의 인텐트 필터에 대한 디폴트 라벨이다.

android:name 서비스를 구현하는 Service 서브클래스의 이름이다. com.example.project.RoomService 처럼 전체 클래스 이름이어야 한다. 하지만 .RoomService와 같이 단축형 이름이라면 <manifest>엘리먼트에 지정된 패키지 이름 끝에 붙여진다.

android:permission 서비스를 런치하거나 바인드를 하 위해 가져야 하는 퍼미션 이름이다. 만약 startsService(), bindService(), stopService()의 호출자가 이 퍼미션을 부여받지 않는다면 이 메쏘느는 작동하지 않으며 인턴트 오브젝트는 서비스에 전달되지 않는다. 이 퍼미션을 설정하지 않으면 <application>퍼미션이 적용되고 <application>퍼미션이 없다면 퍼미션이 적용되지 않는다.


<receiver>

<receiver android:enabled=["true" | "false"]

android:exported=["true" | "false"]

android:icon="drawable resource"

android:label="string resource"

android:name="string"

android:permission="string"

android:process="string" >

. . .

</receiver>

어플리케이션이 브로드캐스트 메시지를 수신할수 있도록 한다. 브로드캐스트 리시버는 애플리케이션의 다른 컴포넌트들이 실행되지 않아도 다른 애플리케이션 또는 시스템에 의해 브로드캐스트 되는 인텐트를 받기 위해 애플리케이션을 활성화 한다.

시스템에게 브로드캐스트 리시버를 알기기 위한 방법으로는 이 엘리먼트를 가지고 매니페스트 파일 안에 선언하는 것과 코드 안에서 동적으로 리시버를 만들어서 Context.registerReceiver() 메쏘드를 사용해서 등록한다.

android:exported 브로드캐스트 리시버가 다른 애플리케이션 소스로부터 메시지를 받을수 있는지를 설정한다. 받을수 있으면 true이고 아니면 false이다. 인텐트 필터가 없으면 디폴트 값은 false이고 인텐트 필터가 있다면 디폴트 값은 true이다.


<provider>

<provider android:authorities="list"

android:enabled=["true" | "false"]

android:exported=["true" | "false"]

android:grantUriPermissions=["true" | "false"]

android:icon="drawable resource"

android:initOrder="integer"

android:label="string resource"

android:multiprocess=["true" | "false"]

android:name="string"

android:permission="string"

android:process="string"

android:readPermission="string"

android:syncable=["true" | "false"]

android:writePermission="string" >

. . .

</provider>

애플리케이션의 일부가 되는 모든 컨텐트 프로바이더를 선언해야 한다. 컨텐트 프로바이더 서브클래스에 대한 이름은 URI authority이다.

android:authorities 데이터를 구분하는 URI authority 목록이다. Authority가 여러 개이면 세미콜론(;)으로 이름을 구분한다. 최소한 하나의 authority가 지정되어야 한다.

android:grantUriPermissions 일시적으로 radPermission, writePermission, 데이터 접근 할수 있게 하려면 ture로 설정하거나 <grant-uri-permission>서브엘리먼트를 정의함으로써 이 기능을 활성화 한다. 퍼미션을 설정하지 않으려면  false로 한다.

android:initOrder 컨텐트 프로바이더가 인스턴스화되어야 하는 순서를 설정한다. 높은 숫자들이 먼저 초기화 된다.

android:permission 클라이언트가 컨텐트 프로바이더의 데이터를 읽거나 쓰기 위해 가져야 하는 퍼미션의 이름이다. 이 애트리뷰트는 읽기와 쓰기 모두에게 하나의 퍼미션을 설정한다. 하지만 readPermission과 writePermission 애트리뷰트가 이것보다 우선순위이다.

android:readPermission 클라이언트가 컨텐트 프로바이더에 쿼리하기 위해 가져야 하는 퍼미션이다.

android:syncable 컨텐트 프로바이더의 제어하에 있는 데이터가 서버 상의 데이터와 동기화되어져야 한다면 true 아니면 false이다.

android:writePermission 클라이언트가 컨텐트 프로바이더에 의해 제어되는 데이터를 변경하기 위해 가져야 하는 퍼미션이다.


<uses-library>

<uses-permission android:name="string" />

어플리케이션에 링크 되어야 하는 외부 라이브러리를 지정한다.

android:name 라이브러리 이름




디폴트 값

Element

Atrribute

디폴트 값

<instrumentation>

android:functionalTest

false


android:handleProfiling

false

<uses-sdk>

android:minSdkVersion

1


android:maxSdkVersion

없음

<supports-screens>

android:smallScreens

true(API Level 7 기준)


android:normalScreens

true(API Level 7 기준)


android:largeScreens

true(API Level 7 기준)


android:anyDensity

true(API Level 7 기준)

<application>

android:allowClearUserData



android:allowTaskReparenting

false


android:debuggable

false


android:enable

true


android:hasCode

true


android:persistent

false


android:process

<manifest>엘리먼트의 package 이름


android:taskAffinity

<manifest>엘리먼트의 package 이름

<activity>

android:alwaysRetainTaskState

false


android:clearTskOnLaunch

false


android:enabled

true


android:excludeFromRecents

false


android:exported

Intent 필터가 없다면 false

Intent 필터가 있다면 true


android:finishOnTaskLaunch

false


android:launchMode

standard


android:multiprocess

false


android:noHistory

false


android:permission

<application>엘리먼트의 퍼미션

<application>퍼미션이 없다면 퍼미션에 의해 보호 되지 않음


android:process

애플리케이션의 패키지 이름


android:stateNotNeeded

false


android:taskAffinity

어플리케이션의 친화력을 상속.

어플리케이션의 디폴트 친화력 이름은 <manifest>엘리먼트의 패키지 이름이다.


android:theme

<application>테마

<application>테마가 없다면 시스템 테마


android:windowSoftInputMode

소프트 키보드 : stateUnspecified

메인 윈도우 : adjustUnspecified

<intent-filter>

android:label

부모 컴포넌트에 설정된 라벨

부모가 라벨을 설정하지 않으면 <application>라벨

<activity-alias>

android:enabled

true


android:exported

인텐트 필터가 없으면 false

인텐트 필터가 있으면 true


android:permission

targetActivity의 퍼미션

targetActivity의 퍼미션이 없다면 퍼미션에 의해 보호되지 않음

<service>

android:enabled

true


android:exported

인텐트 필터가 없으면 false

인텐트 필터가 있으면 true


android:permission

<application>엘리먼트의 퍼미션

<application>퍼미션이 없다면 퍼미션에 의해 보호되지 않음

<receiver>

android:enabled

true


android:exported

인텐트 필터가 없으면 false

인텐트 필터가 있으면 true


android:permission

<application>엘리먼트의 퍼미션

<application>퍼미션이 없다면 퍼미션에 의해 보호되지 않음

<provider>

android:enabled

true


android:exported

인텐트 필터가 없으면 false

인텐트 필터가 있으면 true


android:multiprocess

false


android:process

<application>엘리먼트의 프로세스




Posted by 훈남, 밍공™

댓글을 달아 주세요

일반적인 경우, 안드로이드 용 어플리케이션을 작성하게 되면 여러가지 Activity 들을 생성하게 됩니다. 이때, 가장 골치가 아픈 일 중 하나는 바로 Activity 와 Activity 간의 Flow 를 설계하고 이를 적절하게 구현하는 일입니다. (특히 안드로이드를 사용해보지도 않은 UX 팀과 함께 일하게 되는 경우라면 더욱 그러합니다...)

 기본적으로 안드로이드 플랫폼 상에서 Activity 는 또 다른 Activity 를 시작할 수 있고, 각각의 Activity 는 차곡 차곡 Task 라고 불리우는 Activity Stack 에 쌓이게 됩니다. 사용자는 일반적으로 Back 버튼을 이용해서 현재 화면상에 보이는 Activity 를 종료 시키고, 바로 직전에 사용된 Activity 로 돌아갈 수 있습니다. 안드로이드 펍의 회색님의 말을 빌리자면, 인터넷 브라우저를 통해 웹페이지를 검색하는 것과 유사한 방식입니다. 

 하지만 이러한 방법만으로는 효과적인 UX Flow 를 구축하는데 어려움이있습니다. 다행히, 구글에서는 Activity 를 호출할 때 사용되는 Intent 에 적절한 플래그 값을 설정해서 Activity Stack 을 제어할 수 있는 방법을 제공해 줍니다. 이 플래그들은  FLAG_ACTIVITY 라는 접두어를 갖고 있는데, 종류가 다양해 헷갈리는 수도 있는데, 개인적으로 제가 가장 요긴하게 사용하고 있는 FLAG_ACTIVITY 네 가지를 소개해 봅니다. 

 먼저 FLAG_ACTIVITY_SINGLE_TOP 입니다. 우선 간단하게 그림으로 표현해 보았습니다. A 와 B  두 가지 Activity 가 있는 데, A 라는 Activity 는 B 를 B 라는 Activity 는 다시 자기 자신인 B 를 호출 하는 경우라고 가정해 보겠습니다. 
< FLAG_ACTIVITY_SINGLE_TOP >

 호출하는 Activity B 가 이미 Task 의 가장 앞에 위치하는 경우, 또 하나의 B 를 생성하는 대신, 기존에 존재하는 B Activity 가 재활용됩니다. 이 때 B 가 재활용된다는 것을 개발자가 알아채고 새롭게 전달되는 Intent 를 사용할 수 있도록 B Activity 의 onPause() / onNewIntent() / onResume() 가 순차적으로 호출됩니다. 별 생각없이 동일한 Activity 를 여러번 생성하는 것은 메모리 사용량과 Activity 시작 속도 양쪽 모두에 악영향을 끼칠 수 있습니다. (특히 이미지가 덕지덕지 붙어 있는 Activity 라면). 이런 경우 FLAG_ACTIVITY_SINGLE_TOP 를 적절하게 활용하면 제법 큰 효과를 볼 수 있습니다.

 두 번째는, FLAG_ACTIVITY_NO_HISTORY 플래그입니다. 우선 간단하게 그림으로 표현해 보았습니다. A 와 B  두 가지 Activity 가 있는 데, A 라는 Activity 는 B 를 B 라는 Activity 는 A 를 호출한 후 에 (A->B->A) 사용자가 Back 키를 누르는 경우를 가정해 보겠습니다.
<FLAG_ACTIVITY_NO_HISTORY>

 말 그대로, FLAG_ACTIVITY_NO_HISTORY 로 설정된 Intent 로 시작된 Activity B 는 Task 에 그 흔적을 남기지 않게 됩니다. B 에서 또다른 A 를 시작한 후, Back 을 누르면 일반적인 경우 이전에 실행되었던 B 가 나타나지만, NO_HISTORY 를 사용하는 경우 맨 처음에 실행 되었던 A 가 화면에 표시됩니다. 몇 가지 주의할 점이 있습니다. 우선 NO_HISTORY 를 사용하게 되면 Task 에 해당 Intent 의 정보가 기록되지 않기 때문에, A->B 인 상황 (그림에서 두 번째 단계...) 에서 홈키등을 눌러 다른 Task 로 전환된 후, 다시 본 Task 로 돌아오게 되면, A Activity 가 화면에 표시됩니다. 또한, B Activity 의 onDestroy() 가 호출되는 시점이 조금 애매합니다.일반적인 예상과는 달리, B 에서 또다른 A Activity 를 호출하는 세 번째 단계에서는 onStop 까지만 호출되고, 이 후에 새롭게 호출된 A Activity 가 사라지는 순간 (네 번째 단계) 에서야 onDestroy() 가 호출 됩니다.

 FLAG_ACTIVITY_NO_HISTORY 는 여러가지로 쓸모가 있는데, 특히 특정한 이벤트에 대한 알람등을 위해 다이얼로그 형태로 화면에 표시되는 Activity 들에 적용하기에 편리합니다. (대게의 경우 팝업은 해당 시점에 한번만 보여주면 되니까.)

 다음으로 굉장히 유용한 플래그 두 가지를 동시에 설명해보고자 합니다. FLAG_ACTIVITY_REORDER_TO_FRONT 와 FLAG_ACTIVITY_CLEAR_TOP 플래그입니다. 우선 간략하게 그림으로 살펴 보겠습니다. A Activity 에서 B Activity 를 그리고 B 에서 A 를 호출하는 상황을 가정해보았습니다. (A->B->A)


 FLAG_ACTIVITY_REORDER_TO_FRONT 는 매우 특이하게도 Task 의 순서 자체를 뒤바꿔 줍니다. 이 플래그를 사용하면, 런치하고자 하는 Activity 가 이미 Task 상에 존재하는 경우 해당 Activity 를 새롭게 생성하는 대신, 아래쪽에 위치한 Activity 의 순서를 Task 의 가장 위로 끌어올려줍니다. 따라서 A->B->A 의 순서로 Activity 호출이 일어날때, 새로운 A 가 생성되는 대신 아래쪽에 위치한 A 가 위로 올라와 최종적으로 B->A 의 형태로 Task 가 구성되게 됩니다. 어떤 Activity 에서 특정 Activity 로 점프하는 형식의 Flow 를 구성해야하는 경우 요긴하게 사용될 수도 있지만, Task 의 순서를 뒤섞는 다는 점에서 사용에 주의를 기울일 필요가 있습니다.  (별 생각없이 남발하게 되면 Back 키가를 누를 때 엉뚱한 Activity 가 표시되어 사용자들이 굉장히 혼란스러워 하는 경우가 있습니다.) 

 마지막으로 소개해 드릴 플래그는 바로 FLAG_ACTIVITY_CLEAR_TOP 입니다. 제가 개인적으로 가장 사랑스럽게 생각하는 녀석입니다. 이 플래그가 사용되는 경우  
런치하고자 하는 Activity 가 이미 Task 상에 존재하는 경우, 해당 Activity 위에 존재하는 다른 Activity 를 모두 종료시켜 줍니다. 따라서 A->B->A 로 호출이 일어나는 경우, B Activity 가 종료 되고, A Activity 만 Task 에 남게 됩니다. (A->B->C->A 인 경우에도 마찬가지로 B와 C 가 종료되고 A 만 남게 됩니다.)

  이 Flag 는 특정 어플리케이션의 대쉬보드 (혹은 홈) Activity 를 호출할 때 굉장히 유용하게 사용될 수 있습니다. 즉 하나의 어플리케이션이 하나 혹은 두 가지의 주요한 Activity 와 그 외 특정 값을 선택하는등 단순한 일을 수행하기 위한 여러 개의 Sub-Activity 로 구성되어 있다면, 주요 Activity 를 호출하는데 이 Flag 를 사용함으로서 어플리케이션의 홈버튼등을 손쉽게 구현할 수 있습니다. 또 이 Flag 는 FLAG_ACTIVITY_REORDER_TO_FRONT 와는 달린 Task 의 순서를 뒤섞지 않음으로 사용자에게도 큰 혼란을 주지 않습니다. (사용을 적극 권장합니다.)

 한 가지 주의해야할 점은 A->B->A 형태로 Activity 를 호출 하고자 할 때, 단순히 FLAG_ACTIVITY_CLEAR_TOP 만을 사용하게 되면, 기존에 생성되었던 A Activity 가 종료된 후 (onDestroy() 가 호출됨) 새롭게 A 가 생성 (onCreate()) 됩니다. 만일 기존에 사용된 A Activity 가 계속 사용되기를 원한다면, SINGLE_TOP 플래그와 함께 사용해야 합니다.

 휴... 생각보다 내용이 길어졌네요. 대부분 SDK 문서를 읽어보면 잘 나와있는 내용이라 새로운 내용은 없습니다만... 문서 읽기를 게을리한 덕분에 한창을 고생했던 기억이 떠올라 (특히 CLEAR_TOP) 유용하게 사용한 Flag 를 정리하는 겸 작성해 보았습니다~

저작자 표시
Posted by 훈남, 밍공™

댓글을 달아 주세요

최근에 달린 댓글

최근에 받은 트랙백

글 보관함