Saturday, October 10, 2015

[Android Databass] SQLiteOpenHelper, ContentProvider, OrmLite, AndroidAnnotations @OrmLite - 2

Android에서 Sqlite를 사용하는 것에 있어서 두번째 포스팅입니다. 기본적인 OrmLite Library사용과 AndoridAnnotations를 적용하여 OrmLitef를 사용하는 방법에 대하여 포스팅하도록 하겠습니다.

3. OrmLite

ORM 이라는 의미는 Object Realational Mapping의 약자입니다. OrmLite는 많은 표준 Library의 복잡성과 오버헤드를 피하면서 SqlDatabase를 접근 할 수 있게 하는 경량 Library입니다. 이것은 다양한 JDBC를 지원할뿐만아니라, Sqlite와 함께사용하는 Android OS Database API의 native call 또한 지원한다.(Homepage참고) Orm 에 Java 표준 기술은 Java Persistence API로 JPA가 요즘 많이 사용되고 있다고 한다. Spring과 같은 웹 프로젝트에서 이런 Java Library를 사용하는 것과 같이 Android 계열에서 Sqlite 사용시 Orm 을 사용할 경우 더 편하게 사용할 수있으니 해당 Library는 앞으로 봤을때 사용성이 높은 Library라고 생각합니다.

Github Repository 에 가면 아래의 작성한 소스코드 전체를 확인할 수 있습니다. OrmLite에 대한 상세한 설명은 더 파악한 후에 포스팅하도록 하겠습니다. 이 포스팅에서는 사용법 위주로 설명하도록 하겠습니다.

가장 먼저 gradle에 ormlite에 대한 dependency를 추가해주어야 합니다.

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    compile 'com.android.support:appcompat-v7:23.0.1'
    ...

    compile 'com.j256.ormlite:ormlite-android:4.46'
    ...
}

저는 OrmLiteDBHelper라고 class 이름을 설정하고 해당 class는 OrmLiteSqliteOpenHelper를 상속받아야 합니다. 또한 상속받게 되면 아래와 같이 생성자와 onCreate, onUpgrade에 대해서 implement를 반드시 해줘야 한다. 그리고 SQLiteOpenHelper 에서 해줬던것 처럼 데이터베이스 이름과 버전을 설정해줘야한다. 저는 이 부분에 대해서 Constant Class를 따로 두고 받아오도록 구현하였습니다.

package com.juranoaa.sqlite.common;

public class Constant {
    public static final class SQLite {
        public static final Integer ORM_DB_VERSION = 1;
        public static final String ORM_DB_NAME = "ORMTest.db";
    }
}
package com.juranoaa.sqlite.ormlite;

import android.content.Context;
import android.database.sqlite.SQLiteDatabase;

import com.j256.ormlite.android.apptools.OrmLiteSqliteOpenHelper;
import com.j256.ormlite.support.ConnectionSource;
import com.juranoaa.sqlite.common.Constant;

public class OrmLiteDBHelper extends OrmLiteSqliteOpenHelper{

    public OrmLiteDBHelper(Context context) {
        super(context, Constant.SQLite.ORM_DB_NAME, null, Constant.SQLite.ORM_DB_VERSION);
    }

    @Override
    public void onCreate(SQLiteDatabase database, ConnectionSource connectionSource) {

    }

    @Override
    public void onUpgrade(SQLiteDatabase database, ConnectionSource connectionSource, int oldVersion, int newVersion) {

    }
}

그리고 onCreate와 onUpgrade method에 아래와 같이 구현해야 합니다. onCreate에는 Database생성, onUpgrade에는 Database 삭제후 생성과 같은 함수 내용을 작성해야 합니다. 이 부분을 아래와 같이 작성해줍니다. 이때 사용되는 것은 " TableUtils " 에 정의 되어있고 데이터베이스를 생성해주는 쿼리문을 작성해줍니다.

package com.juranoaa.sqlite.ormlite;

public class OrmLiteDBHelper extends OrmLiteSqliteOpenHelper{

//...

@Override
public void onCreate(SQLiteDatabase database, ConnectionSource connectionSource) {
    try {
        TableUtils.createTable(connectionSource, House.class);
    } catch (SQLException e) {
        Log.e(TAG, e.getMessage(), e);
        throw new RuntimeException(e);
    }
}
// ...

}

여기서 House.class 와 같은 경우는 아래와 같이 정의가 필요합니다. 이렇게 작성해주게 되면 자동으로 CREATE 문을 생성하여 Sqlite Database에 입력해줍니다. 자세한 내용은 Database를 참고 하시기 바랍니다.

package com.juranoaa.sqlite.ormlite;

public class House {

    // auto increment
    @DatabaseField(generatedId = true)
    Integer id;

    @DatabaseField
    String name;

    public House() {
        // must exist
    }
}

그리고 두가지 method를 정의하여 사용할 수 있습니다. getDao(class)의 경우에는 SQLExcpetion이 throw 되는 method이고 getRuntimeExceptionDao(class)은 Exception 에 대해서 RuntimeException으로 처리하여 사용하는 method가 제공됩니다. 이에 대한 구현은 아래와 같이 표현됩니다.

package com.juranoaa.sqlite.ormlite;
// ...

public class OrmLiteDBHelper extends OrmLiteSqliteOpenHelper{
    // ...    
    private RuntimeExceptionDao<House, Integer> houseRuntimeExceptionDao = null;
    // ...
    
    public RuntimeExceptionDao<House, Integer> getHouseDataDao() {
        if (houseRuntimeExceptionDao == null) {
            houseRuntimeExceptionDao = getRuntimeExceptionDao(House.class);
        }
        return houseRuntimeExceptionDao;
    }
    // ...
}

이렇게 구성하면 OrmLite를 사용할 수 있게됩니다. 또한 해당 Library는 apt를 통해 compile 시점에 작동하는 library가 아닌 runtime시에 작동하는 library입니다. 그리고 Activity에서 아래 코드와 같이 사용하면 사용할 수 있습니다.


@EActivity(R.layout.main)
public class AASQLiteActivity extends OrmLiteBaseActivity<OrmLiteDBHelper> {

    @ViewById
    TextView textView;

    @AfterViews
    void afterViews(){
        RuntimeExceptionDao<House, Integer> houseDao = getHelper().getHouseDataDao();
        List<House> houseList = houseDao.queryForAll();
        textView.setText(houseList.toString());

        for(House house : houseList){
            House updateHouse = new House(house.getId(), house.getName()+"_update");
            houseDao.update(updateHouse);
        }
        List<House> updateHouseList = houseDao.queryForAll();
        textView.setText(textView.getText()+updateHouseList);
    }
}

Activity는 OrmLiteBaseActivity를 상속받고 Generic 부분은 앞에서 작성한 클래스 이름이 작성되게 됩니다. (OrmLiteDBHelper) 그리고 getHeleper()를 통하여 OrmLiteDBHelper에서 작성한 getHouseDataDao method를 호출하여 사용하면 된다.

해당 Dao에 대해서 create, update, delete, queryForAll 과 같은 method을 이용하여 SQLite 데이터 베이스에 CRUD 작업을 할 수 있습니다. 이렇게 사용할 경우 상속받을 Activity에 type과 method를 작성을 해야하는데 이런 불편함을 조금 더 개선한게 AndroidAnnotations에 @OrmLite입니다.

4. AndroidAnnotations @OrmLite @EProvider

가장먼저 AndroidAnnotations의 @OrmLite를 사용하기 위해서 Gradle에 추가정보를 입력해야 합니다. 해당 부분은 4.0-SNAPSHOT 기준입니다. 현재 Release 버전인 3.3.2를 사용한다면 기존 apt만 사용해도 사용할 수 있습니다.

def AAVersion = "3.3.2"
dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    compile 'com.android.support:appcompat-v7:23.0.1'
    apt "org.androidannotations:androidannotations:$AAVersion"
    compile "org.androidannotations:androidannotations-api:$AAVersion"
    compile 'com.j256.ormlite:ormlite-android:4.46'
}
def AAVersion = "4.0-SNAPSHOT"
dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    compile 'com.android.support:appcompat-v7:23.0.1'
    apt "org.androidannotations:androidannotations:$AAVersion"
    compile "org.androidannotations:androidannotations-api:$AAVersion"

    compile 'com.j256.ormlite:ormlite-android:4.46'
    apt "org.androidannotations:ormlite:$AAVersion"
    compile "org.androidannotations:ormlite-api:$AAVersion"
}

@OrmLite 사용에 있어서 기존에 앞에 사용하던 Class는 그대로 유지를 하여 사용하면 됩니다. 그리고 객체를 반환했을때 사용할 수 있도록 하는 객체하나가 필요합니다.

package com.juranoaa.sqlite.ormlite;

import com.j256.ormlite.dao.Dao;
import com.j256.ormlite.dao.RuntimeExceptionDao;

public class HouseRuntimeExceptionDao extends RuntimeExceptionDao<House,Integer>{

    public HouseRuntimeExceptionDao(Dao<House, Integer> dao) {
        super(dao);
    }
}

위의 객체를 정의하고 Activity에서 아래와 같이 정의하고 사용하면 @OrmLite Annotation을 사용할 수 있습니다.

@EActivity(R.layout.main)
public class AASQLiteActivity extends Activity{
    ...
    @OrmLiteDao(helper = OrmLiteDBHelper.class)
    HouseRuntimeExceptionDao houseDao;
    ...
}

위의 코드는 Github Repository에서 전체 코드를 확인할 수 있습니다.

이상으로 Android 에서 Database를 접근하는 방법에 대해서 두개의 포스팅에서 검토해보았습니다. ContentProvider의 경우 Android Docs를 보게되면 Application간에 데이터를 공유해야 되는 경우에만 필요하다고 작성되어있습니다. 따라서 CRUD에 대한 쿼리 작성이 불편한 점으로 인해 하나의 Application에서만 사용하는 DB를 ContentProvider로 쓰는것은 올바르지 않다고 생각합니다. 그래서 제 생각에는 OrmLite를 이용하면 조금 더 이런 코드에 대한 리팩토링을 할 수있다고 생각합니다. 이상 끝.

No comments:

Post a Comment