이 게시물을 무단으로 사용하는 행위(비영리, 영리 포함)는 CCL 2.0 저작자 표시-비영리-변경금지 라이센스에 의거하여 금지되어 있습니다. 원본 글의 출처 및 저작자를 표시해 주신다면 글의 스크랩은 자유롭게 하실 수 있습니다. 단, 비영리 목적의 발표(스터디 등)에 위 글을 사용하고 싶으신 분은 제게 미리 메일로 문의 부탁드립니다.
저작권과 관련된 자세한 사항은 이곳을 참조해 주시기 바랍니다.
저작권과 관련된 자세한 사항은 이곳을 참조해 주시기 바랍니다.
데이터베이스 강좌로는 꽤 오래간만에 찾아뵙는군요.
제가 요즘 병행하고 있는 일이 한두개가 아닌데다가, 강좌를 자유롭게(?) 쓸 여건은 되지 않다보니 계속 미뤄지기만 했네요.
아무튼, 이번 강좌에서는 실제로 데이터베이스 어댑터를 생성하여 어플리케이션에 적용하는 것에 대해 알아보겠습니다.
데이터베이스의 어댑터의 역할
"어댑터"에 대한 개념은 예전에 리스트를 설명할 때 처음 등장했습니다. (참고 : 2009/06/08 - [안드로이드 입문/GUI 구성하기] - #11. List 집중공략! - (3) Custom ArrayAdapter를 이용한 ListView)
리스트 어댑터는 실제 데이터와 그 데이터를 표시해주는 리스트뷰 사이에 위치하면서 데이터를 리스트에 표시해주는 역할을 합니다. 즉, 다른 체계를 가지고 있는 개체 사이에서 서로가 호환이 될 수 있도록 적절히 데이터의 형태를 변환해주는 것이 어댑터의 역할이라고 할 수 있죠.
그렇다면, 데이터베이스 어댑터의 역할은 무엇일까요? - 데이터베이스 어댑터 사실 어댑터의 기본 개념과는 약간 다른 개념을 가지고 있습니다. 서로 다른 두 개체를 호환시켜주는 역할이라기보다는, 데이터베이스에 접근하여 수행하는 작업들을 추상화시켜주는 역할을 합니다.
데이터베이스를 다루다보면 데이터베이스에 접근하여 데이터 추가, 수정, 삭제 등의 작업을 하게 되는데 이러한 작업의 내용은 겉으로 드러내지 않아야 데이터베이스 구조의 노출도 막을 수 있고, 쓸데없이 코드를 길게 쓰는 일도 줄어들게 되죠.
일반적인 데이터베이스 어댑터의 구조, 기능
일반적으로 데이터베이스 어댑터는 다음과 같은 구조를 가지고 있습니다.
- 필드 이름들
- 데이터베이스 초기화에 필요한 SQL 문장들
- 데이터베이스 정보 (테이블 이름, 데이터베이스 이름 등)
- 헬퍼 클래스 (SQLiteOpenHelper; 데이터베이스 열기/닫기를 담당)
- 헬퍼 클래스의 인스턴스
- 데이터베이스 (SQLiteDatabase)의 인스턴스
- 데이터베이스 작업에 필요한 메소드들
- 필드 이름들
지난 강좌 (2009/07/04 - [안드로이드 입문/데이터 이용하기] - 데이터베이스 이용하기 - (2) 안드로이드 데이터베이스 기초) 에서 봤던 것처럼, 데이터베이스는 테이블과 테이블 안에 필드(열)과 레코드(행)으로 이루어져있습니다. 이 중, 필드 이름은 앞으로 어댑터 내에서 심심하면 쓰게 됩니다. 데이터베이스를 추가할 때도, 수정할 때도, 테이블을 생성할 때에도 필요하니... 보통 자주 쓰이는 것이 아니죠. 보통, 이렇게 자주 쓰이는 것들은 데이터베이서 어댑터 내에 static final String 형태, 즉 "상수"처럼 저장해놓고 사용합니다.
예)public static final String KEY_NAME = "name"; public static final String KEY_PHONE = "phone"; public static final String KEY_ROWID = "_id";
- 데이터베이스 초기화에 필요한 SQL 문장들
데이터베이스를 처음 생성할 때 필요한 SQL문장들입니다. 일반적으로 테이블을 생성하는 문장이 들어갑니다.
예)
private static final String DATABASE_CREATE = "create table data (_id integer primary key autoincrement,"+ "name text not null, phone text not null);";
- 데이터베이스 정보 (테이블 이름, 데이터베이스 이름 등)
테이블 이름, 데이터베이스 이름, 데이터베이스 버전입니다. 데이터베이스 버전은 나중에 데이터베이스를 업데이트할 때 업데이트 여부를 결정하는 기준이 됩니다.
private static final String DATABASE_NAME = "datum.db"; private static final String DATABASE_TABLE = "data"; private static final int DATABASE_VERSION = 1;
- 헬퍼 클래스 (SQLiteOpenHelper; 데이터베이스 열기/닫기를 담당)
데이터베이스 파일을 열고 닫는 작업을 수행해주는 클래스입니다. 필요하다면 데이터베이스를 생성하고, 업그레이드합니다. 데이터베이스를 생성하는 메소드인 onCreate()와 데이터베이스의 업그레이드를 담당하는 onUpgrade() 메소드를 필수로 구현해야 합니다. (두 메소드 모두 추상 메소드 형태로 선언되어있음)
private class DatabaseHelper extends SQLiteOpenHelper{ public DatabaseHelper(Context context) { super(context, DATABASE_NAME, null, DATABASE_VERSION); // TODO Auto-generated constructor stub } public void onCreate(SQLiteDatabase db){ db.execSQL(DATABASE_CREATE); } public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion){ Log.w(TAG, "Upgrading db from version" + oldVersion + " to" + newVersion + ", which will destroy all old data"); db.execSQL("DROP TABLE IF EXISTS data"); onCreate(db); } }
- 헬퍼 클래스의 인스턴스
헬퍼 클래스는 데이터베이스를 열고 닫는 것을 도와주는 클래스라고 했었죠? 이런 역할을 하는 헬퍼 클래스를 이용하기 위해서는 헬퍼 클래스 형태를 가지는 인스턴스가 있어야겠지요?
private DatabaseHelper mDbHelper;
이렇게 선언한 헬퍼 클래스의 인스턴스는 뒤에서 데이터베이스 어댑터 클래스 내의 데이터베이스를 여는 메소드, 닫는 메소드에서 사용되게 됩니다.
- 데이터베이스(SQLiteDatabase)의 인스턴스
실제 데이터베이스에 접근할 때 사용하는 인스턴스입니다. 이 인스턴스에서 insert(), update(), query(), delete()등의 메소드를 호출하여 원하는 작업을 수행하게 됩니다.
private SQLiteDatabase mDb;
- 데이터베이스 작업에 필요한 메소드들
실제로 데이터베이스를 가지고 수행할 작업들에 대한 메소드입니다. 일반적으로 데이터 추가, 수정, 삭제, 질의(Query) 작업을 수행하게 되므로, 이에 적합한 작업을 수행하는 메소드를 작성합니다. 아래는 예제입니다.
public long createBook(String name, String phone){ // 레코드 생성 ContentValues initialValues = new ContentValues(); initialValues.put(KEY_NAME, name); initialValues.put(KEY_PHONE, phone); return mDb.insert(DATABASE_TABLE, null, initialValues); } public boolean deleteBook(long rowID){ // 레코드 삭제 return mDb.delete(DATABASE_TABLE, KEY_ROWID + "=" + rowID, null) > 0; } public Cursor fetchAllBooks(){ // 모든 레코드 반환 return mDb.query(DATABASE_TABLE, new String[]{KEY_ROWID, KEY_NAME, KEY_PHONE}, null, null, null, null, null); } public Cursor fetchBook(long rowID) throws SQLException{ // 특정 레코드 반환 Cursor mCursor = mDb.query(true, DATABASE_TABLE, new String[]{KEY_ROWID, KEY_NAME, KEY_PHONE}, KEY_ROWID + "=" + rowID, null, null, null, null, null); if(mCursor != null) mCursor.moveToFirst(); return mCursor; } public boolean updateBook(long rowID, String name, String phone){ // 레코드 수정 ContentValues args = new ContentValues(); args.put(KEY_NAME, name); args.put(KEY_PHONE, phone); return mDb.update(DATABASE_TABLE, args, KEY_ROWID + "=" + rowID, null) > 0; }
데이터베이스 어댑터 예제
아래는 데이터베이스 어댑터의 예제입니다. 저장하는 데이터는 String형 데이터 2개입니다.
package com.androidhuman.dbExample;
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 DbAdapter {
public static final String KEY_NAME = "name";
public static final String KEY_PHONE = "phone";
public static final String KEY_ROWID = "_id";
public static final int FIND_BY_NAME = 0;
public static final int FIND_BY_PHONE = 1;
private static final String TAG = "DbAdapter";
private DatabaseHelper mDbHelper;
private SQLiteDatabase mDb; // 데이터베이스를 저장
private static final String DATABASE_CREATE =
"create table data (_id integer primary key autoincrement,"+
"name text not null, phone text not null);";
private static final String DATABASE_NAME = "datum.db";
private static final String DATABASE_TABLE = "data";
private static final int DATABASE_VERSION = 1;
private final Context mCtx;
private class DatabaseHelper extends SQLiteOpenHelper{
public DatabaseHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
// TODO Auto-generated constructor stub
}
public void onCreate(SQLiteDatabase db){
db.execSQL(DATABASE_CREATE);
}
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion){
Log.w(TAG, "Upgrading db from version" + oldVersion + " to" +
newVersion + ", which will destroy all old data");
db.execSQL("DROP TABLE IF EXISTS data");
onCreate(db);
}
}
public DbAdapter(Context ctx){
this.mCtx = ctx;
}
public DbAdapter open() throws SQLException{
mDbHelper = new DatabaseHelper(mCtx);
mDb = mDbHelper.getWritableDatabase();
return this;
}
public void close(){
mDbHelper.close();
}
public long createBook(String name, String phone){
ContentValues initialValues = new ContentValues();
initialValues.put(KEY_NAME, name);
initialValues.put(KEY_PHONE, phone);
return mDb.insert(DATABASE_TABLE, null, initialValues);
}
public boolean deleteBook(long rowID){
return mDb.delete(DATABASE_TABLE, KEY_ROWID + "=" + rowID, null) > 0;
}
public Cursor fetchAllBooks(){
return mDb.query(DATABASE_TABLE, new String[]{KEY_ROWID, KEY_NAME, KEY_PHONE}, null, null, null, null, null);
}
public Cursor fetchBook(long rowID) throws SQLException{
Cursor mCursor =
mDb.query(true, DATABASE_TABLE, new String[]{KEY_ROWID, KEY_NAME, KEY_PHONE}, KEY_ROWID + "=" + rowID, null, null, null, null, null);
if(mCursor != null)
mCursor.moveToFirst();
return mCursor;
}
public boolean updateBook(long rowID, String name, String phone){
ContentValues args = new ContentValues();
args.put(KEY_NAME, name);
args.put(KEY_PHONE, phone);
return mDb.update(DATABASE_TABLE, args, KEY_ROWID + "=" + rowID, null) > 0;
}
}
'데이터 관리 > SQLite3' 카테고리의 다른 글
| 데이터베이스 이용하기 - (3) 데이터베이스 어댑터 만들기 (78) | 2009/08/01 |
|---|---|
| 데이터베이스 이용하기 - (2) 안드로이드 데이터베이스 기초 (31) | 2009/07/04 |
| 데이터베이스 이용하기 - (1) SQL의 기초 (7) | 2009/06/23 |
안드로이드 정보, 강좌를 누구보다 빨리 접하고 싶으신가요?
그렇다면 이메일 구독 혹은
를 통해 업데이트되는 최신 글들을 받아보실 수 있습니다. :)





댓글을 달아 주세요
한번초기화하면 값변경되지못하는걸로 배웠는데 이건 참 당황스럽내요.
2009/10/27 07:31 [ ADDR : EDIT/ DEL : REPLY ]public static final String KEY_NAME = "name";<--이건 KEY_NAME변수에name이란string값이 들어가고 이후론 변경불가로 아는데요...
initialValues.put(KEY_NAME, name);<--KEY_NAME에 name파라미터값을 집어넣는다는건데 먼저변수선언하고 초기화한 위의코드로 인해 에러나지않는것이 뭔가 머리아프게하내요..
KEY_NAME에 값을 집어넣는 것이 아니라,
2009/10/28 03:44 [ ADDR : EDIT/ DEL ]initialValues 객체에 KEY_NAME이라는 키를 가지는 데이터를 넣는 것입니다. initialValues.put(KEY_NAME, name)은 "name"이라는 키, 데이터로는 name 변수의 값을 갖게 되겠죠.
자세한 내용은 API를 참조하세요.http://developer.android.com/reference/android/content/ContentValues.html
KEY_NAME은 테이블의name필드가 들어갔죠;;이(KEY_NAME=)name에 파라미터name의값을 집어넣는다는것을 생각못했네요.(이게 맞는건지모르겠네요;
안드로이드에서 자바문법을 생각하다 그만 엉뚱히게 이해했습니다.자바에서 상수란게 한번 초기화하면 값변경못한다는걸로 배워서 여기서 자꾸이상하게 오해해버리네요;;하하 아무튼 답변감사합니다.
2009/10/28 10:07 [ ADDR : EDIT/ DEL : REPLY ]비밀댓글입니다
2009/12/10 15:25 [ ADDR : EDIT/ DEL : REPLY ]위의 예제는 안드로이드 내의 DB를 사용하는 방법에 대해 설명한 것입니다.
2009/12/10 16:01 [ ADDR : EDIT/ DEL ]어플리케이션 내의 DB를 사용하시려는거라면 위의 예제처럼 별도의 환경설정 없이 바로 데이터베이스와 연동이 가능합니다.
데이터베이스 파일은 폰 내부의 data/data/[패키지명]/database/ 내에 저장되며, sqlite3 툴을 사용하여 데이터베이스를 열어 편집하는 것도 가능합니다.
비밀댓글입니다
2009/12/10 17:46 [ ADDR : EDIT/ DEL : REPLY ]비밀댓글입니다
2009/12/11 16:55 [ ADDR : EDIT/ DEL : REPLY ]DB를 불러온다는게 정확하게 어떤 말씀이신지 모르겠습니다.
2009/12/13 18:28 [ ADDR : EDIT/ DEL ]테이블 내에 저장되어 있는 해당 필드의 값을 불러온다는것을 말씀하시는건지요?
query()메소드를 통해 데이터르 받아오는 단위는 하나의 레코드 단위입니다. 레코드 중에서 어떤 필드의 데이터를 받아올지 지정을 하게되면 그 필드의 데이터만 받아오게 되는것이지요.
그리고.. 데이터베이스는 컴퓨터 내에 저장되는것이 아니라 에뮬레이터 내에 저장됩니다. DDMS의 File Explorer를 통해 확인할 수 있습니다.
비밀댓글입니다
2009/12/15 10:56 [ ADDR : EDIT/ DEL : REPLY ]하나하나씩 보다보면 그리 어렵지 않을거에요~
2009/12/15 12:22 [ ADDR : EDIT/ DEL ]화이팅입니다
ㅎㅎㅎㅎ 데이터베이스를 요로코롬 설명해주니깡 쉽게 느껴지는군요.. 뭐 db야 범위가 끝도 없다 하지만.. 초보자인 저로서 훨 쉽게 이해가 되는군요 역쉬 선행학습효과가 엄청 느껴지는 부분입니다. 감동 `!! ㅋ
2009/12/23 23:36 [ ADDR : EDIT/ DEL : REPLY ]전 요새 DB공부 계속 하면서 좌절만 느끼고있어요 ㅠㅠ
2009/12/24 00:42 [ ADDR : EDIT/ DEL ]DB 자체에서도 지원해주는게 이리 많았는데 쓸줄을 몰라서 개고생한게 생각나서..ㅠㅠ
커니님 강좌 잘보고 있습니다..!! 안드로이드의 초행길을 걷고 있습니다..ㅠ
2009/12/28 11:26 [ ADDR : EDIT/ DEL : REPLY ]근데 위의 소스코드를 그냥 새로운 프로젝트 만들어서 실행 시켰는데 특별한 아이콘이 생기지도 않고 에뮬레이터 상에서 실행이 되지 않는데 위의 결과물은 어떻게 확인할 수 있을까요??
어떤 식으로 프로젝트를 생성하셨는지부터 궁금하네요.
2009/12/28 12:47 [ ADDR : EDIT/ DEL ]위에 있는 코드는 어플리케이션 코드가 아니라 데이터베이서 어댑터 코드만 있기에 당연히 저것만으로는 실행이 되지 않습니다
안드로이드폰 내에 있는 DB를 건드린다고 하셨는데요..
2010/02/05 01:55 [ ADDR : EDIT/ DEL : REPLY ]그럼 만약에 제가 어플리케이션을 만들어서 배포를 하고 업데이트를 하고 싶을 때 안드로이드 폰 내에 있는
DB로는 업데이트를 못하는거 아닌가요?? 업데이트를 디비를 통해서 하고 싶은데.. 그렇다면 웹이나 서버컴을
만들어서 해야되는건가요??
간단한 것이라면 onUpgrade() 메소드 내에서 새 데이터를 넣어주는 식으로 해서 업데이트를 할 수도 있겠죠.
2010/02/05 02:35 [ ADDR : EDIT/ DEL ]하지만 대부분의 경우 웹디비를 연동하여 사용합니다.
비밀댓글입니다
2010/04/04 02:51 [ ADDR : EDIT/ DEL : REPLY ]db파일 직접 겁근은 권한이 있지 않아 불가능합니다.
2010/04/04 13:31 [ ADDR : EDIT/ DEL ]그렇기 때문에 Conttent Provider를 사용하여 접근하게 되지요.
ContentProvider쪽을 참고하세요.
강좌 정말 잘보고 있습니다! 하지만 궁금한 것이 있는데요~
2010/04/09 21:02 [ ADDR : EDIT/ DEL : REPLY ]위의 예제는 DB를 건들이기 위한 메소드나 디비헬퍼라는건 알겠는데요
실제로 저 클래스를 어케 인스턴스를 구현하고, 또 어케 불러야하는지 약간 초보적일지는 몰라도
그게 궁금합니다~
틀은 갖춰져 있는데 실제로 어케 써야하는지 몰라서 고민입니다;;;;;
예를 들어 다른 클래스에서 디비에 name과 number를 저장하고자 할때
private DBAdapter MyDB;
한뒤 MyDB.createBook("홍길동", "010-1234-5678" );
이렇게만하면 끝인가요??
현재 저 위의 예제를 DBManager라는 클래스에 넣은 상태고
이클립스의 DDMS의 파일익스플로러로 보았을때
저의 어플 패키지 아래엔 database 라는 폴더도 없고, data.db 도 없는 상태입니다
걍 lib만 있는 상태죠,
근데 처음 디비를 구축했을때 table이 자동으로 생기는것 같더라고요
답변좀 꼭 부탁드립니다!!~ ^^*
저 부분 설명은 준비중입니다
2010/04/16 13:44 [ ADDR : EDIT/ DEL ]조만간 좋은 소식이 있을거에요~
디비 파일이 생성되는 시점음 onCreate() 메소드가 호출될 때 생성됩니다. 기존에 디비파일이 없을 경우에 생성하게 되는 것이구요.
따라서 처음 실행시에 생성되게됩니다.
Context 가 하는 일은 연결된 애의 정보를 가져오는건가요?
2010/04/14 20:36 [ ADDR : EDIT/ DEL : REPLY ]Context는 매우 심오한 앱니다 -_-;;
2010/04/16 13:45 [ ADDR : EDIT/ DEL ]액티비티, 서비스 등 주요 클래스의 상위 클래스이며....
쉽게는 하나의 "실행 단위"에 필요한 정보들을 담고 있는 객체라 보시면 됩니다.
위의 예제 실행해볼만한 어플리케이션 코드는 없을련지요? ㅠㅠ 구해볼수 있으면 좋겠네요 ^-^ 만약 있다면 메일로 부탁드려도 될련지요? hoyoung205@naver.com으로 보내주세요~~ 답변 기다리구 있겠습니다ㅎㅎ
2010/05/09 23:20 [ ADDR : EDIT/ DEL : REPLY ]개인적으로 준비하고 있는 책의 예제코드로 들어가있습니다
2010/05/10 13:07 [ ADDR : EDIT/ DEL ]데이터베이스 어댑터를 사용하는 에제는 다른 곳에서도 찾을 수 있어요~~
커니님께서 보고 계시는 책 추천 받을수 있을련지요? ^-^
2010/05/10 18:12 [ ADDR : EDIT/ DEL : REPLY ]커니님 죄송하지만 질문이 하나 더 있는데요^^ 제가 만든 데이터베이스 파일을 바탕화면으로 부르고 그 파일을 SQLite Manager로 수정하고 나서 export 시키면 기존 events.db에서 events.sql로 바꿔서 수정된 데이터 베이스를 다시 폰으로 불러올수가 없습니다. 이 문제 어떻게 해결해야 하는지 혹시 아시나요? 그러니까 한마디로 수정후 확장자가 바꿔서 불러올 수 없는 문제입니다. 답변 기다리구 있을께요... ^^
2010/05/10 21:55 [ ADDR : EDIT/ DEL : REPLY ]글쎄요.... 그렇게 수정은 안해봐서 잘 모르겠네요 ^^;
2010/05/10 22:18 [ ADDR : EDIT/ DEL ]위 예제 소스좀 얻을 수 있을까요?? 레이아웃이랑 그외 매니패스트 가 어떻게 되어있는지 몰라서 에러가 자꾸 나네요..ㅜㅜ 공부하고 싶은데 부탁드립니다
2010/05/11 03:41 [ ADDR : EDIT/ DEL : REPLY ]비밀댓글입니다
2010/05/22 15:45 [ ADDR : EDIT/ DEL : REPLY ]다른 데이터베이스로 이동한다는 것 자체가 어찌보면 말이 안된다고 볼 수 있겠습니다. 매우 복잡한 데이터베이스를 사용하지 않는 이상 데이터베이스 파일 자체는 일반적으로 하나만 사용합니다.
2010/05/22 20:03 [ ADDR : EDIT/ DEL ]말씀하신 문제는 데이터베이스 쪽 기본적인 공부를 조금 더 해보신다면 답이 나올 것 같네요. 그 다음 안드로이드 데이터베이스 중에서도 기초 중의 기초, Cursor 및 Cursor 내의 메소드를 어떻게 사용하는가, 그리고 전반적으로 데이터베이스를 열고 닫는 등의 동작에 대해 알아보시는게 좋겠네요.
개인적으로는 데이터베이스를 직접 사용하는 것 보다는 컨텐트 프로바이더를 직접 만들어 사용하는게 만들기는 어려워도 사용하기에는 수월할 것 같네요.
다음 강좌 빨리 올려주세요..ㅠㅠ
2010/06/27 16:29 [ ADDR : EDIT/ DEL : REPLY ]그리고 전체 소스가 공개된 예제 강좌도 올려주시면 많은 도움이 되겠네요..ㅠㅠ
졸작하는데 DB 맡아서 하기론 친구놈들이 엄헌 곳으로 취직됐다고 도망가서 공부하는데 어렵네요;
안타깝습니다 ㅠㅠ
2010/07/01 11:18 [ ADDR : EDIT/ DEL ]디비쪽은 개발자 사이트의 NotePad 예제를 보셔도 괜찮을것 같습니다 ㅎㅎ
어플을 처음 설치할때만 테이블을 만드는건 어떻게 하나요~?
2010/07/26 14:32 [ ADDR : EDIT/ DEL : REPLY ]예외처리로 테이블이 없을때 만들도록 하면 되나요~?
데이터베이스 어댑터의 onCreate() 메소드 자체가 데이터베이스 파일이 없을 때 데이터베이스를 생성하면서 호출됩니다.
2010/07/26 15:42 [ ADDR : EDIT/ DEL ]이 부분에서 테이블 생성을 해주면 됩니다.
답변 감사합니다. ^^ 한가지만 더 질문해도 될까요.
2010/07/29 14:47 [ ADDR : EDIT/ DEL : REPLY ]어플을 삭제하면 시스템에서 자동으로 데이터베이스를 삭제해주나요.?
어플을 삭제하면 DB도 자동 삭제됩니다.
2010/07/29 16:58 [ ADDR : EDIT/ DEL : REPLY ]실제 어플을 지우고 재 설치 해보니 기존에 있던 DB Data가 초기화 됐네요~
혹시 데이터 베이스 에 잇는 자료를 배열 로 가져오려면 어떻게 하면 될까요?
2010/08/03 15:32 [ ADDR : EDIT/ DEL : REPLY ]cursor을 쓰면 될까요?
커서로 쿼리 날린 후에 하나하나 배열로 복사해 오면 되겠습니다
2010/08/04 23:48 [ ADDR : EDIT/ DEL ]저기 제가 위의 예제 파일을 돌렸는데........DDMS에 data/data/패키지명안에 database가 없고 lib만 있는데...
2010/08/11 16:50 [ ADDR : EDIT/ DEL : REPLY ]왜 DB파일이 생기지 않는건가요!? 좀 알려주세요/////////
그리고 이게 돌아가긴 하는거죠?!
좀 알려주세요.....ㅜㅜ 부탁드립니다....ㅠㅠ
데이터베이스를 생성하지 않아서 해당 폴더 및 파일이 생성되지 않은 것 같습니다. 데이터베이스 생성 코드가 제대로 작성되어 있는지 확인해주세요!
2010/08/11 17:46 [ ADDR : EDIT/ DEL ]위에 잇는 어뎁터를 listview에 뿌리고싶은데요 그림처럼...
2010/08/17 14:49 [ ADDR : EDIT/ DEL : REPLY ]수정,삭제만 할수잇게끔요...어떻게 해야하나요?
dbadapter가 arrayadapter같은 개념인가요? ..sqlite에 관해서 3일째입니다..후압
데이터베이스를 표시하려면 CursorAdapter를 사용하시면 됩니다~
2010/08/25 19:42 [ ADDR : EDIT/ DEL ]이렇게 좋은 자료들을 올려주셔서 감사합니다.
2010/08/25 21:24 [ ADDR : EDIT/ DEL : REPLY ]다른 책 보면서 공부하고 있는데 이 책만든사람이 컴퓨터에 대해 기본적인 소양있는 사람이 볼거라 생각하고 만들어서 그런지 좋은책임에도 불구하고 이해하기 힘든 부분이 있었는데 그런부분은 이 블로그를 참조하니 도움이 되네요 ㅎㅎㅎㅎ 앞으로도 자주들를게요 ㅎㅎㅎ
ㅎ 방금 감사합니다 하고 글을 올렸는데 이바로위에 8/17일에 올린질문에 적혀있는 질문이 멀 물어보는건가요? ㅎ
2010/08/25 21:27 [ ADDR : EDIT/ DEL : REPLY ]저도 책에서 cursoradapter를 쓴다는 걸 봤는데 대체 어떤경우에 쓰는건지 좀체 감이 잡히지 않네요 ㅎ
내부 DB (SQLite DB)에 있는 정보를 쿼리하게 되면 그 결과는 Cursor 객체로 받게 됩니다. 그것을 리스트뷰에 표시하려면 어댑터가 필요한데, 이 때 CursorAdapter 를 사용합니다.
2010/08/26 03:18 [ ADDR : EDIT/ DEL ]비밀댓글입니다
2010/08/27 15:11 [ ADDR : EDIT/ DEL : REPLY ]수정은 Cursor.update() 메서드를 사용합니다. 수정하고자 하는 항목의 id를 받아온 후, ContentValues 객체에 수정할 항목의 데이터를 넣고 update() 메서드의 인자로 넣어주면 해당 항목의 데이터가 수정됩니다.
2010/08/27 15:08 [ ADDR : EDIT/ DEL ]비밀댓글입니다
2010/08/27 15:15 [ ADDR : EDIT/ DEL ]그 문제는 데이터베이스의 문제가 아니라 EditText의 문제입니다.
으로 입력한 내용을 초기화해주면 됩니다 
2010/08/27 15:51 [ ADDR : EDIT/ DEL ]데이터 입력시 EditText.setText(""
비밀댓글입니다
2010/08/27 21:19 [ ADDR : EDIT/ DEL : REPLY ]일목요연한 설명보고 정말 많은 도움이 되었습니다
2010/10/08 06:20 [ ADDR : EDIT/ DEL : REPLY ]그런데 한가지
아래 구문들은 왜 넣는거죠?
public DbAdapter(Context ctx){
this.mCtx = ctx;
}
public DbAdapter open() throws SQLException{
mDbHelper = new DatabaseHelper(mCtx);
mDb = mDbHelper.getWritableDatabase(); //이 부분은 헬퍼를 통해 디비를 읽고쓰겠다는걸 알려주는 것이고..
return this;
}
DatabaseHelper 생성자 부분을 보시면 Context의 인스턴스를 사용하는 걸 확인하실 수 있습니다
2010/10/08 10:52 [ ADDR : EDIT/ DEL ]커니님 수고하십니다. 눈팅만 하다가 처음 질문을 올려봅니다
2010/10/12 13:51 [ ADDR : EDIT/ DEL : REPLY ]현제 어플 개발에 참여 중입니다만, 실 수행 코드에서는 에러가 발행하지 않으나...contentprovider관련 Instrumentest 시에 leak가 발생해서 조사중입니다. 직접 질문입니다만,
저의 인식이라면
db.open하고
cursor.open();후에 필요한 처리수행후 커서객체에 담아서 어뎁터를 이용하여 결과를 화면에 표시하게 되는 인식입니다. 그후
cursor.close();를 콜하여 커서를 닫아 주는 인식입니다.
하지만.. 여기서 의문이 cursor.close();만 콜하여주는것으로 db.close를 수행 해 주지 않아도
동작이 정상적으로 이루어지는 상태입니다. cursor.close();만으로도 디비연결이 자연스럽게 닫혀지는것인지
아니면 제가 알지 못하는 부분의 처리가 Android제공 API속에 (OpenHelper)에 명시되어있는것인지 잘 모르겠습니다.
현제 자신의 인식이라면 Instrumentest 시에 leak가 발생한 원인이 테스트 코드에서는 이 해당부분 (leak가 발생부분)의 처리가 db오픈후 아무것도 하지 않은체 열린상태로 정상적으로 닫지 않아서 발행한것이라는 추론이라서...
제가 여쭙고 싶은것은 ( 디비 오픈후 커서 오픈 --> 처리 --> 커서 클로즈 ) 많으로도 실행시에는 문제가 없는것이 어떤 백단 처리가 수행 되어지는것인지(자신이 모르는) 그래서 이부분에 실 코드에서는 알지 못했지만.. 테스트 코드에서는 leak가 발생한것인지? 입니다.
많이 바쁜 와중에 여쭙게 되어 죄송합니다. 항상 건강하시길 바라며, 저의 모자란 인식 부분이 있다면
가르침 부탁 드립니다.
컨텐트 프로바이더를 사용할 때의 장점 중 하나가, 데이터베이스를 열고 닫는 동작이 자동으로 이루어진다는 것입니다.

2010/10/12 19:46 [ ADDR : EDIT/ DEL ]즉, 말씀하신 대로 컨텐트 프로바이더 자체에서 데이터베이스를 자동으로 열고 닫아주기 때문에, 개발자는 커스 객체만 잘 닫아주면 누수 현상을 방지할 수 있습니다.
커니님 강좌를 보고 기초적인 db이용과 listview이용방법을 배워갑니다
2010/10/16 00:02 [ ADDR : EDIT/ DEL : REPLY ]제가 db table을 3-5개 사용하는 어플을 만드는중인데요
안드로이드는 db를 파일처럼 관리하더라고요
여러개의 table을 생성하고 연계시키려면
현재 머리속에서는
table당 어뎁터를 만들고 연계는 코딩부분에서 연계시키려 생각 중입니다.
위의 방법은 너무 깔끔하지 못할것 같아서요
안드로이드 자체에서 외래키등 지원을 하는지요
그리고 한 어뎁터에서 여러개의 table을 생성가능한가요? database_name 이 같고 database_table의 이름이
다르다면 가능하지 않을지 싶은데요
테이블당 어댑터를 만들 필요도 없고, 추천하지는 않지만 여러 개의 데이터베이스 파일을 하나의 어댑터로 관리할 수도 있습니다. 구현하기 나름이지요
2010/10/16 12:48 [ ADDR : EDIT/ DEL ]안드로이드에서는 SQLite3를 사용하므로... DBMS에서 지원하는 기능은 그 쪽을 참고하시면 좋을 듯 합니다.
제가 여기 나와있는 예제를 바탕으로 table을 3개를 생성하였습니다.
2010/10/20 04:21 [ ADDR : EDIT/ DEL : REPLY ]그런데 처음생성한 table은 정상작동을 합니다.
그러나 db.execSQL(CREATE_TABLE2); db.execSQL(CREATE_TABLE3);
과같이 3개를 1번째 table과 동일한 양식과 방법으로 생성해주었습니다.
그런데 동일하게 하여 생성한 table임에도 불구하고 list에 뿌려주는 SimpleCursorAdapter 를 사용할 경우
ndroid.database.sqlite.SQLiteException: no such column: _id <<<과 같은 런타임 에러를 뿜습니다.
table이 생성되지 않은것일까요? log로 찍어보면 형이 다른것을 insert문장 수행시 삽입 에러가 뜨긴합니다.
여러개의 table을 관리할수 있는 간단한 방법 여쭐수 있을까요?
sqlite3 같은 툴로 테이블이 제대로 생성되었는지 우선 확인해보는 것이 우선인 듯 합니다. 어댑터를 사용하려면 해당 테이블에 _id 컬럼이 있어야 하는데, 에러 메시지로 봐선 그놈이 없다 하는 것 같군요.
2010/10/20 10:05 [ ADDR : EDIT/ DEL ]커니님 답변감사드립니다. 글은 써놓고 이제야 확인해보네요 ^^;
;
2010/10/25 17:37 [ ADDR : EDIT/ DEL : REPLY ]커니님 개인적인 질문하나 드릴게요
table1 table2
title data title data part date
현금 0 현금 3000
카드 0 카드 3000
현금 -3000
현금 -5000
카드 -10000
위와같이 table2개가 잇을경우
table 1은 초기값이 위와같이 0으로 table이 create될때 insert문으로 초기값이 주어집니다
update문으로 table1 의 data는
(select SUM(data) from table2 where ='x'
위에서 x는 cursor를 이용 table1의 모든 title을 반환받아
title값 하나를 string에 저장해서 매개변수로 넘겨줍니다)
위와같은 생각을 하고잇는데 생각보다 어렵네요
Cursor c3 = aDbHelper.fetch();
c3.moveToFirst();
String msg;
while(!c3.isAfterLast()){
msg = c3.getString(0);
aDbHelper.updateRow(msg);
c3.moveToNext();
}
c3.close();
public Cursor fetch(){
return mDb.query(DATABASE_TABLE, new String[] {KEY_TITLE}, null, null, null, null, null);
}
public void updateRow(String x){
mDb.execSQL("update account SET data = ( select SUM(data) from item where title = '"+x+"' ) where title = '"+x+"'"
}
위와 같이 구성해봤는데 account 의 data가 널값으로 입력되는듯하네요 data를 not null로 세팅해서 오류 발생하고요
혹 아래가 아래와 같은 쿼리문의 결과를 바로 적용시킬 방법도 존재하나요?
public Cursor fetch2sum2(String x){
return mDb.rawQuery("Select SUM(data) From item Where title = '"+x+"'", null);
}
만약 테이블을 2개 생성시, data1, data2 일경우,
;
;
2010/11/05 09:56 [ ADDR : EDIT/ DEL : REPLY ]db.execSQL("DROP TABLE IF EXISTS data1"
db.execSQL("DROP TABLE IF EXISTS data2"
이렇게 넣어야하는건가요? 너무 초보적인 질문입니다. ^^;;
DROP은 테이블을 삭제할때 사용하는 명령어이고... CREATE를 사용하셔야 합니다
2010/11/10 11:23 [ ADDR : EDIT/ DEL ]커니님 기본적인 질문 하나 할께요 :D
?
2010/11/10 03:02 [ ADDR : EDIT/ DEL : REPLY ]이미 있는 .db 파일을 포함시켜서 어플을 만들고 싶은데.
sd카드에 넣으면 다른 사용자들은 이용을 하지 못할까 싶어서요..
그건 어디 폴더에 넣고 불러와야 하나요
assets라는 폴어데 db파일을 넣어서 배포할 수도 있고, 아니면 앱 다운로드 후 최초 실행시 DB를 인터넷에서 다운로드하도록 하는 방법도 있습니다.
2010/11/10 11:25 [ ADDR : EDIT/ DEL ]작은 용량의 DB라면 assets 폴더에 넣는 것이 편합니다 ㅎㅎ
커니님 강좌 잘보고있습니다.
2010/11/12 16:53 [ ADDR : EDIT/ DEL : REPLY ]제가 제일 이해가 안되는 부분이 예제처럼 Context Menu 에서 edit 텍스트를 선택시
edit 화면으로 넘어갈때 해당 db 인자를 어떻게 가지고 가는지 궁금하거든요...
혹시 이예제 소스 공개 좀 해주시면 안될까요??
아니면 약간의 힌트라도...ㅠㅠ onContextItemSelected 부분이 어떻게 처리되었는지 알고 싶습니다.
수고하세요.
onContextItemSelected() 의 인자로 id를 받는데, 이것을 통해 데이터베이스 내 해당 레코드의 id를 얻을 수 있습니다.


2010/11/12 22:30 [ ADDR : EDIT/ DEL ]이걸 이용하면 데이터베이스에 쿼리를 통해 해당 레코드의 정보를 받아오는 것이 가능합니다
그리고 이 코드 예제는 조만간 공개할 예정입니다! ㅎㅎ
출간 예정인 책의 예제로 포함되어 있는데, 작업 완료되는대로 블로그에 올리겠습니다
xml에 만들어 놓은 edittext에다가 이름이랑 전화번호를 써서 db테이블 생성은 어떻게 해야 하나요? ㅠ 코드에다가 미리 안쓰고
2010/12/21 16:26 [ ADDR : EDIT/ DEL : REPLY ]비밀댓글입니다
2011/01/07 15:36 [ ADDR : EDIT/ DEL : REPLY ]제 책의 예제 소스코드에 유사한 작업을 하는 애플리케이션이 있습니다.
2011/01/07 16:46 [ ADDR : EDIT/ DEL ]http://androidhuman.tistory.com/436 에 있는 소스코드 중 6장의 MyBookmark, MyBookmark_2 예제를 보시면 도움이 되실겁니다.
강좌 잘봤습니다.
2011/01/19 23:14 [ ADDR : EDIT/ DEL : REPLY ]그런데 잘 이해가 안되는 부분이 있어서 질문 드립니다.
private class DatabaseHelper extends SQLiteOpenHelper{
부분에서
데이터 베이스 열거나 생성하기 위해서 설계한 클래스라고 하셨는데 굳이 SQLiteOpenHelper 상속할 필요가 있는 것인지 궁금합니다...
SQLIteOpenHelper는 말 그대로 데이터베이스 생성, 업그레이드, 열기 등을 수행해주는 기능을 포함하고 있습니다.
2011/01/20 01:49 [ ADDR : EDIT/ DEL ]데이터베이스를 사용하기 위해 DB를 여는 것 뿐만 아니라 데이터 추가, 삭제, 수정 등의 기능을 넣기 위해 이 클래스를 상속받는 것입니다.
public DbAdapter open() throws SQLException{
2011/01/28 15:30 [ ADDR : EDIT/ DEL : REPLY ]mDbHelper = new DatabaseHelper(mCtx);
mDb = mDbHelper.getWritableDatabase();
return this;
}
부분에서
getWritableDatabase() 뭐하는 메소드인가요???
http://developer.android.com/reference/android/database/sqlite/SQLiteOpenHelper.html#getWritableDatabase()
2011/01/28 17:43 [ ADDR : EDIT/ DEL ]참고하세요.
커니님 SQLiteOpenHelper 사용시 Delete와 Update가 간헐적으로만 작동하는데 원인을 모르겠습니다. 도와주시면 감사하겠습니다.
2011/01/29 20:33 [ ADDR : EDIT/ DEL : REPLY ]질문은 안드로이드 펍에 올려놓았습니다. (이걸로 이틀째 삽질중입니다.)
꼭 좀 해결해주세요. ㅠㅠ;
http://www.androidpub.com/android_dev_qna/1254194
p.s : 토스트도 작동을 안하는데 미치겠네요.
디버깅을 한번 해보시는것을 추천드립니다.
2011/01/31 12:43 [ ADDR : EDIT/ DEL ]이런문제는 디버깅을 해보면서 원인을 찾아야 무엇이 문제인지 제대로 알 수 있습니다.
해결했습니다. 아는동생이 도와줬네요. 디버깅 해보니 SQL에서 rowID의 autoIncrement 때문이더군요.;;
2011/01/31 22:21 [ ADDR : EDIT/ DEL : REPLY ]에러 없이 잘 돌아가는데 뭐가 문제인지 잘 모르겠습니다.분명히 DB파일도 생성되었구요.
; // 여기서 a값이 0이 나옵니다.. insert가 잘 안된거 같은데;;
2011/02/10 21:01 [ ADDR : EDIT/ DEL : REPLY ]일단 c.getCount가 무조건 0이 나오네요 ;;
<메인 액티비티 onCreate안>
this.gdb=new GroupDBHelper(this);
gdb.open();
gdb.insert("새폴더", item.ISBN);
int a=gdb.getCount("새폴더"
<DB 어댑터>
public class GroupDBHelper {
public static final String KEY_NAME="name";
public static final String KEY_ISBN="ISBN";
public static final String KEY_ID="_id";
public static final String DB_NAME="RM_DB.db";
public static final String DB_TABLE="GROUP";
public static final int DB_VERSION=1;
private static final String ClassName=GroupDBHelper.class.getSimpleName();
private static final String[] COLS=new String[]{
KEY_ID,KEY_NAME,KEY_ISBN };
public static final String DB_CREATE="create table "+DB_TABLE+" (_id integer primary key autoincrement,"+
"name text not null, ISBN text not null);";
private SQLiteDatabase db;
private DBOpenHelper dbOpenHelper;
private final Context mCtx;
private class DBOpenHelper extends SQLiteOpenHelper{
public DBOpenHelper(Context context){
super(context,GroupDBHelper.DB_NAME,null,GroupDBHelper.DB_VERSION);
}
@Override
public void onCreate(SQLiteDatabase db) {
// TODO Auto-generated method stub
try{
db.execSQL(DB_CREATE);
}catch(SQLException e)
{
Log.e("DB",GroupDBHelper.ClassName, e);
}
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVer, int newVer) {
// TODO Auto-generated method stub
db.execSQL("DROP TABLE IF EXISTS "+GroupDBHelper.DB_TABLE);
this.onCreate(db);
}
}
// end inner class
public GroupDBHelper(Context context){
this.mCtx=context;
}
public GroupDBHelper open()throws SQLException{
dbOpenHelper=new DBOpenHelper(mCtx);
db=dbOpenHelper.getWritableDatabase();
return this;
}
public void cleanup(){
if(this.db!=null){
this.db.close();
this.db=null;
}
}
public void insert(String name,String ISBN){
ContentValues values=new ContentValues();
values.put(KEY_NAME, name);
values.put(KEY_ISBN,ISBN);
this.db.insert(GroupDBHelper.DB_TABLE, null, values);
}
public void update(long id,String name,String ISBN){
ContentValues values=new ContentValues();
values.put(KEY_NAME, name);
values.put(KEY_ISBN,ISBN);
this.db.update(GroupDBHelper.DB_TABLE, values, KEY_ID+"="+id, null);
}
public void delete(long id){
this.db.delete(GroupDBHelper.DB_TABLE, KEY_ID+"="+id, null);
}
public int getCount(String name){
Cursor c=null;
int count=0;
try{
c=this.db.query(true, GroupDBHelper.DB_TABLE, GroupDBHelper.COLS, KEY_NAME+"="+name,
null, null, null,null,null);
if(c.getCount()>0){
count=c.getCount();
}
}catch(SQLException e){
Log.v("DB", GroupDBHelper.ClassName, e);
}finally{
if(c!=null && !c.isClosed()){
c.close();
}
}
return count;
}
public ArrayList<String> getAllName(){
ArrayList<String> arr=new ArrayList<String> ();
Cursor c=null;
try{
c=this.db.query(GroupDBHelper.DB_TABLE, GroupDBHelper.COLS,
null, null, null,null,null);
int count=c.getCount();
c.moveToFirst();
for(int i=0;i<count;i++)
{
String str=c.getString(1);
if(arr.contains(str)==false){
arr.add(str);
}
c.moveToNext();
}
}catch(SQLException e){
Log.v("DB", GroupDBHelper.ClassName, e);
}finally{
if(c!=null && !c.isClosed()){
c.close();
}
}
return arr;
}
public ArrayList<String> getISBN(String name){
ArrayList<String> arr=new ArrayList<String> ();
Cursor c=null;
try{
c=this.db.query(true, GroupDBHelper.DB_TABLE, GroupDBHelper.COLS, KEY_NAME+"="+name,
null, null, null,null,null);
if(c.getCount()>0){
c.moveToFirst();
int num=c.getCount();
for(int i=0;i<num;i++)
{
if(name==c.getString(1))
{
arr.add(c.getString(2));
}
c.moveToNext();
}
}
}catch(SQLException e){
Log.v("DB", GroupDBHelper.ClassName, e);
}finally{
if(c!=null && !c.isClosed()){
c.close();
}
}
return arr;
}
}
이럴땐 코드보다는 DB 파일을 직접 확인해보는게 더 빠릅니다. aqlite3 툴을 사용하여 데이터베이스를 직접 확인해보시고, 레코드가 들어가 있는지 먼저 확인해보시는걸 추천드립니다.
2011/02/11 14:24 [ ADDR : EDIT/ DEL ]좋은글 출처를 표시하고 블로그에 담아갑니다. ^^
2013/04/16 11:03 [ ADDR : EDIT/ DEL : REPLY ]