2012년 6월 30일 토요일

액티비티 팝업으로 띄우기(테마 적용)

이번 프로젝트를 하면서 팝업창이 일반 Alert Dialog가 아닌, 직접 UI를 구현한 형식의 Dialog창이여야 했습니다.
AlertDialog.Builder 클래스를 사용해서 View를 넣어주는 방식도 있었지만, 문제는 Dialog창에서 프로그램 로직을 돌려야 할 경우 어떻게 처리해야 하는가에 대한 부분이였습니다.

예를 든다면 팝업창이 뜨면서 서버로부터 데이터를 받아와서 팝업창의 내용을 뿌려야 한다던가 하는 식의 처리였죠.

웹에서 자료를 찾다 보니 딱 제가 원하는 방식이 있어서 정리해 봅니다.

먼저 팝업으로 사용할 Activity를 하나 만들어야 합니다.
그리고 AndroidMenifest.xml에서 해당 클래스를 Activity로서 등록하는 Attribute에android:theme="@android:style/Theme.Dialog" 라는 속성을 추가해 줍니다.
  1. <ACTIVITY  
  2.     android:name="Activity 클래스 이름"  
  3.     android:theme="@android:style/Theme.Dialog"></ACTIVITY>  

그런 다음 팝업창으로 동작할 해당 Activity 클래스의 소스파일에 onApplyThemeResource 라는 메소드를 재정의 해 줍니다.
  1. @Override  
  2. protected void onApplyThemeResource(Resources.Theme theme, int resid, boolean first)  
  3. {  
  4.     super.onApplyThemeResource(theme, resid, first);  
  5.           
  6.     // no background panel is shown  
  7.     theme.applyStyle(android.R.style.Theme_Panel, true);  
  8. }  

이제 이 부모창에서 이 Activity를 Intent를 통해서 startAcvity() 메소드로 호출하면 팝업창으로서 동작합니다. 물론 페이지의 디자인이 화면의 전체 사이즈보다 작아야 하겠죠.

startActivityForResult() 메소드를 활용하면 팝업창으로 부터의 결과를 부보창이 받아볼 수 도 있게 됩니다.


출처 : http://hoyanet.pe.kr/544

Activity Life Cycle 알아보기


1. Activity Lifecycle

Activity Lifecycle이란!
액티비티의 시작, 실행, 활성, 비활성화, 정지, 종료되는 일련의 과정을 Activity Lifecycle이라고 한다.
어플리케이션의 액티비티가 포그라운드, 백그라운드 될 때 마다 상태가 끊임없이 변경이 된다.

액티비티는 스택에서 관리된다!
시스템의 액티비티들은 액티비티 스택에 의해 관리 된다. 새로운 액티비티가 시작되면 스택의 최상단에 놓여지게 되고 running 액티비티가 된다.
전의 액티비티는 스택에서 새로운 액티비티 아래에 놓여지게 된다. 그리고 새로운 액티비티가 존재할 때까지 포그라운드에 오지 않는다.
http://developer.android.com/guide/topics/fundamentals/tasks-and-back-stack.html 의 그림들만 보셔도 스택에서 관리가 되는지 명료하게 확인 가능 합니다. 


액티비티는 필수적으로 네 개의 상태가 있다.

<그림1 . Activity State>

- 액티비티가 스크린의 포그라운드(스택 최상단)에 있다면 active 또는 running 상태이다.
- 액티비티가 포커스를 잃는다면 그러나 아직 화면에 보여진다면(전체 화면이 아니거나 투명한 액티비티인 경우는 paused 상태이다. 
paused 액티비티는 완전히 살아있다.(모든 상태와 멤버 정보를 유지하고 window manager에 추가되어 남아있다.) 그러나, 극단적인 낮은 메모리 상황이 되면 시스템에 의해 죽여진다.
- 액티비티가 다른 액티비티에 의해 완전히 가려진 상태라면 stopped 된 것이다. 아직 모든 상태와 멤버 정보를 가지고 있다. 그러나 사용자에게 더 이상 보여지지 않고 window에 가려져 있고 메모리가 필요할 때 마다 시스템에 의해 killed 된다.
- 액티비티가 paused 또는 stopped 된다면 시스템은 finish를 요청하거나 단순히 프로세스의 killing에 의해 메모리로부터 액티비티를 죽을 수 있다. 다시 사용자에게 보여질 때, 완벽히 restart 그리고 이전 상태로 restore 되야 한다. 

Activity Lifecycle 이렇게 돌아갑니다. 



<그림2. Activity Lifecycle>

Lifecycle callback 메서드에 대해 알아봅시다.

(1) onCreate(Bundle savedInstanceState)
액티비티를 초기화한다. 중지했다가 재시작하면 액티비티의 이전 상태 정보인 Bundle이 전달된다.
Bundle에 따라 초기화가 다를 경우 onCreate()에서 Bundle 객체 받아 처리한다.

(2) onRestart()
재시작 될 때 호출된다.

(3) onStart()
액티비티가 사용자에게 보이기 직전에 호출된다.

(4) onResume()
사용자와 상호작용을 하기 직전에 호출된다.

(5) onPause()
다른 액티비티가 실행될 때 호출된다.
이 메서드가 리턴되어야 새 액티비티가 활성화된다.

(6) onStop()
액티비티가 사용자에게 보이지 않게 될 때 호출된다.
(7) onDestroy()
액티비티가 파괴될 때 호출된다.
시스템에 의해 강제 종료 여부는 isFinishing()메서드로 조사 가능하다.


(8) onSaveInstanceState(Bundle outputState)
강제종료시 호출된다. onPause()전에 호출된다.

(9) onRestoreInstanceState(Bundle savedInstanceState)
강제종료 후 다시 재시작 될 때 onResume() 전에 호출된다.
onStart()메서드 다음으로 호출되므로 필요한 모든 초기화가 완료된 후에 안전하게 복구할 수 있는 시점이다.



종료 형태에 따라 호출되는 메서드가 틀려져요!

(1) 정상종료
finish() 호출이나 Back 키를 누를 경우 사용자의 입력에 의한 작동이기때문에 정상적인 종료가 된다.

onPause() -> onStop() -> onDestroy()
onCreate() -> onStart() -> onResume() 

 (2) 강제종료
메모리 부족 현상이나 가로,세로 전환시 같은 강제적인 종료를 할 경우가 있다.
onSaveInstanceState()를 통해 임시적인 데이터를 Bundle 객체를 통해 저장한다.
onCreate()와 onRestoreInstanceState()를 통해 Bundle 객체를 가져온다.

onSaveInstanceState() -> onPause() ->onStop() -> onDestroy()
onCreate() ->onStart() ->onRestoreInstanceState() -> onResume()

<질문> Home 키를 누를 경우 onDestroy()가 안되고 onPause(), onStop()까지만 호출 됩니다. 왜 그럴까요? 


* 참고
Bundle
문자열로 된 키값과 임의 타입의 값을 저장하는 일종의 맵이다.

*참고 자료

* 참고 소스
 public class ActivityLifecycleExam1 extends Activity {

    private static final String TAG = "ActivityLifeCycle";
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.i(TAG, "onCreate()");
        if(savedInstanceState != null){
            String value = savedInstanceState.getString("state");
            Log.i(TAG, "state = " + value);
        }
        
        setContentView(R.layout.scrollbar1);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        Log.i(TAG, "onDestroy()");
    }

    @Override
    protected void onPause() {
        super.onPause();
        Log.i(TAG, "onPause()");
    }

    @Override
    protected void onRestart() {
        super.onRestart();
        Log.i(TAG, "onRestart()");
    }

    @Override
    protected void onResume() {
        super.onResume();
        Log.i(TAG, "onResume()");
    }

    @Override
    protected void onStart() {
        super.onStart();
        Log.i(TAG, "onStart()");
    }

    @Override
    protected void onStop() {
        super.onStop();
        Log.i(TAG, "onStop()");
    }
    
    @Override
    protected void onRestoreInstanceState(Bundle savedInstanceState) {
        super.onRestoreInstanceState(savedInstanceState);
        Log.i(TAG, "onRestoreInstaceState()");
        if(savedInstanceState != null){
            String value = savedInstanceState.getString("state");
            Log.i(TAG, "state = " + value);
        }
    }

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        Log.i(TAG, "onSaveInstanceState()");
        outState.putString("state", "ALIVE");
    }
}


마무리

액티비티 생명주기에 따라 각각의 메서드에서 처리해주어야 부분에 대한 이해가 확실해져야 합니다.
그리고 종료 방식에 따라 Bundle을 통해 데이터 처리 부분도 확실한 이해가 필요합니다.
직접 많은 코딩 훈련과 시행착오를 통해 확실히 이해하셨으면 합니다.
그럼 모두 열 코딩 하세요.^^



출처 : http://blog.daum.net/mellowwind/10853728

2012년 6월 29일 금요일

안드로이드 파일 입출력 경로 얻기




애플리케이션을 제작하다 보면 파일을 입/출력 기능을 구현해야 하는 경우가 있습니다. 파일 입/출력을 수행하려면 파일의 경로를 꼭 알아야 하는데, 안드로이드에서 파일을 저장할 수 있는 경로는 다양합니다. 

가장 크게 애플리케이션 데이터가 저장되는 영역(일반적으로 '내부 저장소(Internal Storage)'라 불림)와 사진, 비디오, 데이터 등을 저장하는 영역(일반적으로 '외부 저장소(External Storage)(주1)'라 불림)으로 나뉠 수 있으며, 각 영역별로 다시 캐시 데이터가 저장되는 영역, 데이터베이스가 저장되는 영역 등으로 나뉩니다.

(주1) 외부 저장소는 사용자 데이터(사진, 동영상, 등)이 저장되는 영역입니다. 일반적으로 이는 단말기의 외장 SD카드를 지칭하지만, 단말기에 따라서는 이 영역이 외장 SD카드가 아닌 단말기 내부에 탑재되어 있는 경우도 있었습니다. (넥서스S가 이에 해당) 또는, 단말기 내에 탑재된 외장 메모리 영역 외에 별도의 SD카드도 지원하는 단말기도 존재합니다. (갤럭시S가 이에 해당)

내부 저장소는 각 애플리케이션에서만 데이터를 읽고 쓸 수 있지만, 외부 저장소에는 특정 애플리케이션에서만 사용하는 애플리케이션 고유 영역과 공용 영역이 각각 존재합니다. 애플리케이션 고유 영역에는 각 애플리케이션에서 사용하는 데이터를 저장하며, 이 영역에 저장된 내용은 애플리케이션이 삭제될 때 같이 삭제됩니다. 

공용 영역에는 사진, 비디오, 기타 파일 등을 저장하며 애플리케이션의 삭제에 영향을 받지 않습니다. 하지만, 외부 저장소에 저장된 데이터는 애플리케이션 고유 영역에 저장되어 있더라도 다른 애플리케이션에서 해당 데이터에 접근하는 것이 가능합니다.

각 영역의 경로가 필요할 때마다 해당 경로를 직접 써서 사용할 수도 있겠지만, 번거롭기도 하고 각 유형에 해당하는 경로를 그 때마다 찾아봐야 하므로 시간도 많이 소요됩니다. 이러한 이유로 안드로이드에서는 데이터가 저장되는 주요 경로를 간편하게 얻는 메서드를 제공합니다. 

내부 저장소
1. 캐시(Cache) 저장 영역
캐시 디렉터리에는 애플리케이션에서 필요한 임시 파일들이 저장됩니다.

API
File Context.getCacheDir()
내부 저장소의 캐시 디렉터리 경로를 반환합니다.
내부 저장소의 캐시 디렉터리 경로는 다음과 같이 구성됩니다.

/data/data/[패키지 이름]/cache

패키지 이름이 com.androidhuman.app 일 경우, 이 애플리케이션의 캐시 디렉터리 경로는 다음과 같습니다.

/data/data/com.androidhuman.app/cache

2. 데이터베이스(Database) 파일
애플리케이션에서 사용하는 데이터베이스 파일들이 저장됩니다.

API
File Context.getDatabasePath(String name)
데이터베이스 파일의 경로를 반환합니다. 인자로 데이터베이스 파일의 이름을 넘겨줍니다.
데이터베이스 파일이 저장되는 경로는 다음과 같이 구성됩니다.

/data/data/[패키지 이름]/databases

패키지 이름이 com.androidhuman.app 일 경우, 데이터베이스 파일은 다음 경로에 저장됩니다.

/data/data/com.androidhuman.app/databases

3. 일반 파일 저장 영역
데이터베이스와 캐시를 제외한 애플리케이션에서 사용하는 일반 파일이 저장되는 영역입니다. 이 경로는 Context.openFIleOutput(String, int)를 사용하여 생성되는 파일이 저장되는 경로와 동일합니다.

API
File Context.getFilesDir()
애플리케이션에서 사용하는 일반 파일들이 저장되는 경로를 반환합니다.
파일이 저장되는 경로는 다음과 같이 구성됩니다.

/data/data/[패키지 이름]/files

패키지 이름이 com.androidhuman.app 일 경우, 일반 파일은 다음 경로에 저장됩니다.

/data/data/com.androidhuman.app/files

애플리케이션에서 사용하는 각 일반 파일들의 경로를 가져오려면 다음 메서드를 사용합니다.

API
File Context.getFileStreamPath(String name)
일반 파일이 저장된 공간에서 특정 이름을 가지는 파일의 경로를 반환합니다. 인자로 확장자를 포함한 파일 이름을 넘겨줍니다.
파일의 경로는 다음과 같이 구성됩니다.

/data/data/[패키지 이름]/files/[파일이름]

패키지 이름이 com.androidhuman.app 이고 파일 이름이 filename.ext일 경우, 파일의 경로는 다음과 같습니다.

/data/data/com.androidhuman.app/files/filename.ext


외부 저장소-공용 영역
1. 최상위 경로 얻기
외부 저장소(일반적으로 SD카드)의 최상위 경로를 의미합니다.

API
static File Environment.getExternalStorageDirectory()
외부 저장소의 최상위 경로를 반환합니다.
2.2 (Froyo) 이상을 기준으로 반환되는 최상위 경로는 일반적으로 다음과 같습니다.

/mnt/sdcard


2. 특정 데이터를 저장하는 영역
여러 애플리케이션에서 공용으로 사용할 수 있는 데이터들을 저장합니다. 데이터의 유형에 따라 별도의 디렉터리를 사용합니다.

API
static File Environment.getExternalStoragePublicDirectory(String type)
데이터 유형에 따른 외부 저장소의 저장 공간 경로를 반환합니다. 인자로 디렉터리의 유형을 넘겨줍니다.
안드로이드에서는 총 7개 데이터 유형에 대한 표준 저장 경로를 제공합니다. Environment.getExternalStoragePublicDirectory()의 인자로 넘겨줄 수 있는 인자 및 각 인자의 경로는 다음과 같습니다.

 인자명설명  경로
 Environment.DIRECTORY_ALARMS  알람으로 사용할 오디오 파일을 저장합니다. /mnt/sdcard/Alarms
 Environment.DIRECTORY_DCIM 카메라로 촬영한 사진이 저장됩니다. /mnt/sdcard/DCIM
 Environment.DIRECTORY_DOWNLOADS 다운로드한 파일이 저장됩니다. /mnt/sdcard/Download
 Environment.DIRECTORY_MUSIC 음악 파일이 저장됩니다. /mnt/sdcard/Music
 Environment.DIRECTORY_MOVIES 영상 파일이 저장됩니다. /mnt/sdcard/Movies
 Environment.DIRECTORY_NOTIFICATIONS 알림음으로 사용할 오디오 파일을 저장합니다. /mnt/sdcard/Notifications
 Environment.DIRECTORY_PICTURES 그림 파일이 저장됩니다. /mnt/sdcard/Pictures
 Environment.DIRECTORY_PODCASTS 팟캐스트(Poacast) 파일이 저장됩니다. /mnt/sdcard/Podcasts
이 영역에 데이터를 저장하기 전에, 해당 디렉터리가 존재하는지 필히 확인해야 합니다. 이를 확인하기 위해 File.mkdirs()를 사용하여 디렉터리가 없을 경우 새 디렉터리를 생성합니다. 디렉터리가 존재하지 않을 경우 FileNotFoundException이 발생합니다.

외부 저장소-애플리케이션 고유 영역
1. 특정 데이터를 저장하는 영역
애플리케이션 고유 영역에도 공용 영역과 마찬가지로 각 데이터 유형별로 데이터를 저장하는 표준 디렉터리를 제공합니다. 

API
File Context.getExternalFilesDir(String type)
애플리케이션 고유 영역의 데이터 유형에 따른 외부 저장소의 저장 공간 경로를 반환합니다. 인자로 디렉터리의 유형을 넘겨줍니다.
각 경로의 역할은 공용 영역과 동일합니다.

 인자명경로 
 Environment.DIRECTORY_ALARMS /mnt/sdcard/Android/data/[패키지 이름]/files/Alarms
 Environment.DIRECTORY_DCIM  /mnt/sdcard/Android/data/[패키지 이름]/files/DCIM
 Environment.DIRECTORY_DOWNLOADS  /mnt/sdcard/Android/data/[패키지 이름]/files/Downloads
 Environment.DIRECTORY_MUSIC  /mnt/sdcard/Android/data/[패키지 이름]/files/Music
 Environment.DIRECTORY_MOVIES  /mnt/sdcard/Android/data/[패키지 이름]/files/Movies
 Environment.DIRECTORY_NOTIFICATIONS  /mnt/sdcard/Android/data/[패키지 이름]/files/Notifications
 Environment.DIRECTORY_PICTURES  /mnt/sdcard/Android/data/[패키지 이름]/files/Pictures
 Environment.DIRECTORY_PODCASTS  /mnt/sdcard/Android/data/[패키지 이름]/files/Podcasts
 null  /mnt/sdcard/Android/data/[패키지 이름]/files

2. 캐시 데이터를 저장하는 영역
애플리케이션에서 사용하는 임시 데이터를 외부 저장소에 저장합니다.

API
File Context.getExternalCacheDir()
외부 저장소의 캐시 디렉터리를 반환합니다.
외부 저장소의 캐시 저장 경로는 일반적으로 다음과 같이 구성됩니다.

/mnt/sdcard/Android/data/[패키지 이름]/cache

패키지 이름이 com.androidhuman.app 일 경우, 캐시 저장 경로는 다음과 같습니다.

/mnt/sdcard/Android/data/com.androidhuman.app/cache





Sqlite database 안드로이드 2


<목표>  [안드로이드] SQLite데이터베이스 이용하기
  
 오늘은 안드로이드 개발에 있어서 없어서는 안될 데이터베이스의 사용법에 대해 알아보겠습니다.
안드로이드는 모바일 환경에 알맞은 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_NAMEnullDATABASE_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_TABLEnull, initialValues);
    }
 
    public boolean deleteNote(long rowId) {
 
        Log.i("Delete called""value__" + rowId);
        return mDb.delete(DATABASE_TABLEKEY_ROWID + "=" + rowId, null) > 0;
    }
 
    public Cursor fetchAllNotes() {
 
        return mDb.query(DATABASE_TABLEnew String[] { KEY_ROWIDKEY_TITLE,
                KEY_BODY }, nullnullnullnullnull);
    }
 
    public Cursor fetchNote(long rowId) throws SQLException {
 
        Cursor mCursor =
 
        mDb.query(trueDATABASE_TABLEnew String[] { KEY_ROWIDKEY_TITLE,
                KEY_BODY }, KEY_ROWID + "=" + rowId, nullnullnullnull,
                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)를 만들고, 엑티비티에서는 이 클래스를 생성하여 데이터베이스를 직접 사용할 수 있게 합니다. 간단한 샘플 코드를 이용하여 자신의 데이터베이스 테이블에 맞게 수정하여 사용하면 간단히 데이터를 저장할 수 있는 환경이 됩니다.