Android 저장소 : 데이터베이스에 보관하기

timothy jeong·2021년 11월 17일
0

Android with Kotlin

목록 보기
49/69

대부분의 앱이 데이터를 만들고 저장하고 다양한 방법으로 가공하여 서비스 한다. 이때 앱의 데이터는 대부분 외부 서버에 저장해 놓고 통신으로 주고받지만 휴대용 기기의 특성상 네트워크가 불안정한 상황도 고려해야 하므로 기기에 저장하는 방법도 알아야 한다.

데이터베이스에 보관하기

안드로이드 폰에서 이용하는 데이터베이스 관리 시스템은 오픈소스로 만들어진 SQLite(sqlite.org) 이다. SQLite 는 테이블의 데이터를 앱의 저장소에 파일로 저장하며 외부 앱에서는 접근할 수 없다. 코드에서는 SQL 질의문만 작성하면 되고 실제 데이터는 SQLite 가 관리해준다.

쿼리문 작성하기

SQLite 를 사용하려면 SQLiteDatabase 라는 API를 이용해야한다. openOrCreateDatabase() 함수를 호출해서 SQLiteDatabase 를 얻는다. 이 객체에 포함된 아래 함수를 이용해 쿼리문을 실행할 수 있다.

  • public void execSQL(String sql, Object[] bindArgs)
  • public Cursor rawQuery(String sql, String[] selectionArgs)

둘 다 첫번째 매개변수로는 sql 문을 보내고, 두번째 매개변수로는 sql 문의 ? 문자에 대응하는 값을 배열로 전달한다.

execSQL 함수는 create, alter, drop, insert, update, delete 문을 실행하는 함수이다. rawQuery 함수는 데이터를 조회할 때 주로 사용한다. 이 함수가 반환하는 Cursor 객체는 테이블에서 조회한 행의 집합이다.

val db = openOrCreateDatabase("testDB", Context.MODE_PRIVATE, null)

db.execSQL("create table USER_TB(" +
            "_id integer primary key autoincrement," +
            "name not null," +
            "phone)")

db.execSQL("insert into USER_TB (name, phone) values (?,?)", arrayOf("a","0100"))

val cursor = db.rawQuery("select * from USER_TB", null)

조회한 행의 열 데이터를 가져오려면 먼저 Cursor 객체로 행을 선택하고 그 행의 열 데이터를 가져온다. Cursor 객체로 행을 선택할 때는 moveTo~ 로 시작하는 다음 함수를 이용한다. 이 함수들은 선택한 행이 있으면 true 를 반환하고, 없으면 false 를 반환한다.

  • public abstract boolean moveToFirst() : 첫번째 행을 선택한다.
  • public abstract boolean moveToLast() : 마지막 행을 선택한다.
  • public abstract boolean moveToNext() : 다음 행을 선택한다.
  • public abstract boolean moveToPrevious() : 이전 행을 선택한다.
  • public abstract boolean moveToPosition(int position) : 매개변수로 지정한 위치의 행을 선택한다.

Cursor 객체로 선택한 행의 열 데이터를 가져오려면 타입에 따라 getString(), getInt() 등의 함수를 이용한다. 이 함수의 매개변수에는 가져올 데이터가 저장된 열의 인덱스를 전달한다.

  • public abstract String getString(int columnIndex)
  • public abstract int getInt(int columnIndex)
  • public abstract double getDouble(int columnIndex)

모든 행을 훑으면서 데이터를 가져오려면 moveToNext 로 loop 를 돌리면서 모든 데이터를 저장하면 된다.

val nameList = mutableListOf<String>()
val phoneList = mutableListOf<String>()
while (cursor.moveToNext()) {
    nameList.add(cursor.getString(0))
    phoneList.add(getString(1))
}

execSQL, rawQuery 를 사용하지 않고 직접 insert, update, delete, query 함수를 사용해도 된다. 이 함수는 쿼리문의 각 항목을 매개변수로 대압하면 쿼리문으로 만들어 실행해준다.
즉, String sql 매개변수가 필요없다는 것이다.

  • public long insert (String table, String nullColumnHack, ContentValues values)

  • public int update (String table, ContentValues values, String whereClause, String[] whereArgs)

  • delete(String table, String whereClause, String[] whereArgs)

  • query(boolean distinct, String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy, String limit)

insert(), update() 함수의 매개변수에서 ContentValues 객체는 열 데이터의 집합이다. Map 객체처럼 키 - 값 형태로 데이터를 저장하는데, 이때 키에는 테이블의 열 이름을 지정한다.
더 자세한 사용법은 필요하면 찾아보자.

데이터베이스 관리하기

SQLite 데이터베이스를 이용할 때는 질의문을 실행해야 하므로 반드시 SQLiteDatabase 객체를 이용해야 한다. 그런데 추가로 SQLiteOpenHelper 클래스를 이용하면 데이터베이스 프로그램을 좀 더 구조적으로 작성할 수 있다.

SQLiteOpenHelper 클래스는 데이터베이스를 관리(create, alter, delete)하는 코드를 추사화한다. 이런 관리 코드를 SQLiteOpenHelper 클래스에 작성하고 데이터를 조작하는 코드는 실제 필요한 곳에 작성해 성격이 다른 두 코드를 분리할 수 있다.

SQLiteOepnHelper 는 추상클래스이므로 이를 상속받아 작성해야 한다.

class DBHelper(context: Context) : SQLiteOpenHelper(context, "testDB", null , 1) {

    // 앱이 설치된 후 SQLiteOpenHelper 클래스가 이용되는 순간 한 번 호출된다.
    override fun onCreate(db: SQLiteDatabase?) {
        // 데이터베이스에 테이블을 생성하는 코드를 작성.
    }

    // 생성자에 지정한 DB 버전 정보가 변경될 때마다 호출한다.
    override fun onUpgrade(db: SQLiteDatabase?, oldVersion: Int, newVersion: Int) {
        // 테이블의 스키마(데이터의 구조, 표현 방법, 관계 등)를 변경하는 코드를 작성.
    }
}

SQLiteOpenHelper 생성시 넘겨주는 두번째 매개변수는 db의 이름 , 네번째는 DB의 버전 정보이다.

SQLiteOepnHelper 를 이용하면 SQLiteDatabase 객체도 Helper 를 통해서 얻어야 한다. writableDatabase 이나, readableDatabase 속성으로 SQLiteDatabase 객체를 얻는다.

val db : SQLiteDatabase = DBHelper(this).writableDatabase

추가

안드로이드 저장소

profile
개발자

0개의 댓글