안드로이드 앱에서 내부 데이터베이스를 사용할 때 필요한 API는 android.database.sqlite 패키지로 제공됩니다.
SQLite 예제 프로젝트 https://github.com/kwanulee/AndroidProgramming/tree/master/examples/SQLiteDBTest
public final class UserContract {
public static final String DB_NAME="user.db";
public static final int DATABASE_VERSION = 1;
private static final String TEXT_TYPE = " TEXT";
private static final String COMMA_SEP = ",";
// To prevent someone from accidentally instantiating the contract class,
// make the constructor private.
private UserContract() {}
/* Inner class that defines the table contents */
public static class Users implements BaseColumns {
public static final String TABLE_NAME="Users";
public static final String KEY_NAME = "Name";
public static final String KEY_PHONE = "Phone";
public static final String CREATE_TABLE = "CREATE TABLE " + TABLE_NAME + " (" +
_ID + " INTEGER PRIMARY KEY" + COMMA_SEP +
KEY_NAME + TEXT_TYPE + COMMA_SEP +
KEY_PHONE + TEXT_TYPE + " )";
public static final String DELETE_TABLE = "DROP TABLE IF EXISTS " + TABLE_NAME;
}
}
SQLiteOpenHelper는 추상 클래스 이므로, 서브클래스에서 생성자와 아래의 콜백 메소드를 재정의 해야함
생성자
SQLiteOpenHelper(
Context context, // DB 생성 컨텍스트, 보통 메인 액티비티
String name, // DB 파일 이름
SQLiteDatabase.CursorFactory factory, // 표준커서 사용시 null
int version) // DB 버전
콜백 메서드
콜백 메소드 | 설명 |
---|---|
onCreate() | DB가 처음 만들어질 때 호출됨. 테이블을 생성하고 초기 레코드를 삽입한다. |
onUpgrade() | DB 업그레이드 시 (DB버전을 올린 후 재시작 시) 호출됨. 기존 테이블 삭제 및 생성하거나 ALTER TABLE로 스키마를 수정한다. |
[주의]
생성된 DB는 애플리케이션과 관련된 전용 디스크 공간(/data/data/패키지/databases)에 저장되므로, 다른 애플리케이션이 액세스할 수 없음
예제 코드
public class DBHelper extends SQLiteOpenHelper {
final static String TAG="SQLiteDBTest";
public DBHelper(Context context) {
super(context, UserContract.DB_NAME, null, UserContract.DATABASE_VERSION);
}
@Override
public void onCreate(SQLiteDatabase db) {
Log.i(TAG,getClass().getName()+".onCreate()");
db.execSQL(UserContract.Users.CREATE_TABLE);
}
@Override
public void onUpgrade(SQLiteDatabase db, int i, int i1) {
Log.i(TAG,getClass().getName() +".onUpgrade()");
db.execSQL(UserContract.Users.DELETE_TABLE);
onCreate(db);
}
...
DB 접근 시 SQLiteOpenHelper 객체의 다음 메서드를 호출하여 SQLiteDatabase 객체를 얻는다.
메서드 | 설명 |
---|---|
getReadableDatabase() | 읽기 위해 DB open. |
getWritableDatabase() | 읽고 쓰기 위해 DB open. DB가 없거나 버전 변경 시 onCreate(), onUpgrade()가 호출됨. 권한이 없거나 디스크 용량 부족 시 실패한다. |
SQLiteDatabase 객체의 다음 메소드를 통해 SQL문 실행
예제 코드 (INSERT)
public void insertUserBySQL(String name, String phone) {
try {
String sql = String.format (
"INSERT INTO %s (%s, %s, %s) VALUES (NULL, '%s', '%s')",
UserContract.Users.TABLE_NAME,
UserContract.Users._ID,
UserContract.Users.KEY_NAME,
UserContract.Users.KEY_PHONE,
name,
phone);
getWritableDatabase().execSQL(sql);
} catch (SQLException e) {
Log.e(TAG,"Error in inserting recodes");
}
}
예제 코드 (DELETE)
public void deleteUserBySQL(String _id) {
try {
String sql = String.format (
"DELETE FROM %s WHERE %s = %s",
UserContract.Users.TABLE_NAME,
UserContract.Users._ID,
_id);
getWritableDatabase().execSQL(sql);
} catch (SQLException e) {
Log.e(TAG,"Error in deleting recodes");
}
}
예제 코드 (UPDATE)
public void updateUserBySQL(String _id, String name, String phone) {
try {
String sql = String.format (
"UPDATE %s SET %s = '%s', %s = '%s' WHERE %s = %s",
UserContract.Users.TABLE_NAME,
UserContract.Users.KEY_NAME, name,
UserContract.Users.KEY_PHONE, phone,
UserContract.Users._ID, _id) ;
getWritableDatabase().execSQL(sql);
} catch (SQLException e) {
Log.e(TAG,"Error in updating recodes");
}
}
예제 코드 (SELECT)
public class DBHelper extends SQLiteOpenHelper {
...
public Cursor getAllUsersBySQL() {
String sql = "Select * FROM " + UserContract.Users.TABLE_NAME;
* return getReadableDatabase().rawQuery(sql,null);
}
Cursor 객체를 통한 쿼리 결과 접근
쿼리 결과는 결과셋 자체가 리턴되지 않으며 위치를 가리키는 커서(Cursor)로 리턴된다
메서드 | 설명 |
---|---|
close | 결과셋을 닫는다. |
getColumnCount | 컬럼의 개수를 구한다 |
getColumnIndex | 이름으로부터 컬럼 번호를 구한다. |
getColumnName | 번호로부터 컬럼 이름을 구한다. |
getCount | 결과셋의 레코드 개수를 구한다. |
getInt | 컬럼값을 정수로 구하며 인수로 컬럼 번호를 전달한다. |
getDouble | 컬럼값을 실수로 구한다. |
getString | 컬럼값을 문자열로 구한다. |
moveToFirst | 첫 레코드 위치로 이동하며, 결과셋이 비어있을 시 false를 리턴한다. |
moveToLast | 마지막 레코드 위치로 이동하며, 결과셋이 비어있을 시 false를 리턴한다. |
moveToNext | 다음 레코드 위치로 이동하며, 마지막 레코드이면 false를 리턴한다. |
moveToPrevious | 이전 레코드로 이동하며, 첫 레코드이면 false를 리턴한다. |
moveToPosition | 임의의 위치로 이동한다. |
public class MainActivity extends AppCompatActivity {
private DBHelper mDbHelper;
...
private void viewAllToTextView() {
TextView result = (TextView)findViewById(R.id.result);
Cursor cursor = mDbHelper.getAllUsersBySQL();
StringBuffer buffer = new StringBuffer();
while (cursor.moveToNext()) {
buffer.append(cursor.getInt(0)+" \t");
buffer.append(cursor.getString(1)+" \t");
buffer.append(cursor.getString(2)+"\n");
}
result.setText(buffer);
}
...
SQLiteDatabase의 관련 메소드
예제코드 (insert)
public long insertUserByMethod(String name, String phone) {
SQLiteDatabase db = getWritableDatabase();
ContentValues values = new ContentValues();
values.put(UserContract.Users.KEY_NAME, name);
values.put(UserContract.Users.KEY_PHONE,phone);
return db.insert(UserContract.Users.TABLE_NAME,null,values);
}
예제코드 (delete)
public long deleteUserByMethod(String _id) {
SQLiteDatabase db = getWritableDatabase();
String whereClause = UserContract.Users._ID +" = ?";
String[] whereArgs ={_id};
* return db.delete(UserContract.Users.TABLE_NAME, whereClause, whereArgs);
}
예제코드 (upate)
public long updateUserByMethod(String _id, String name, String phone) {
SQLiteDatabase db = getWritableDatabase();
ContentValues values = new ContentValues();
values.put(UserContract.Users.KEY_NAME, name);
values.put(UserContract.Users.KEY_PHONE,phone);
String whereClause = UserContract.Users._ID +" = ?";
String[] whereArgs ={_id};
return db.update(UserContract.Users.TABLE_NAME, values, whereClause, whereArgs);
}
예제코드 (query)
public Cursor getAllUsersByMethod() {
SQLiteDatabase db = getReadableDatabase();
* return db.query(UserContract.Users.TABLE_NAME,null,null,null,null,null,null);
}
SimpleCursorAdapter를 이용하여 간편하게 리스트 뷰(어댑터 뷰)에 SELECT 결과를 출력
SimpleCursorAdapter (Context context,
int layout, // 어댑터 뷰 항목 표현을 위한 레이아웃
Cursor c, // 검색 결과를 가리키는 커서
String[] from, // 검색 결과에서 표시할 테이블 열들
int[] to, // 테이블 열의 값을 출력할 뷰 ID
int flags) // 보통은 0
예제
public class MainActivity extends AppCompatActivity {
private DBHelper mDbHelper;
...
private void viewAllToListView() {
Cursor cursor = mDbHelper.getAllUsersByMethod();
SimpleCursorAdapter adapter = new SimpleCursorAdapter(getApplicationContext(),
R.layout.item, cursor, new String[]{
UserContract.Users._ID,
UserContract.Users.KEY_NAME,
UserContract.Users.KEY_PHONE},
new int[]{R.id._id, R.id.name, R.id.phone}, 0);
ListView lv = (ListView)findViewById(R.id.listview);
lv.setAdapter(adapter);
lv.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
Adapter adapter = adapterView.getAdapter();
mId.setText(((Cursor)adapter.getItem(i)).getString(0));
mName.setText(((Cursor)adapter.getItem(i)).getString(1));
mPhone.setText(((Cursor)adapter.getItem(i)).getString(2));
}
});
lv.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
}
item.xml for SimpleCursorAdapter
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="5dp">
<TextView
android:id="@+id/_id"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="5dp"
android:textColor="@color/colorAccent"
android:gravity="center"
/>
<TextView
android:id="@+id/name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="5dp"
android:textColor="@color/colorPrimaryDark"
android:layout_weight="1"
android:gravity="center"
/>
<TextView
android:id="@+id/phone"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="5dp"
android:textColor="@color/colorPrimaryDark"
android:layout_weight="1"
android:gravity="center"
/>
</LinearLayout>