본문 바로가기
Kotlin

23. 코틀린 Sqlite/SQLiteOpenHelper

by NaHyungMin 2020. 4. 16.

package com.example.quiz

 

import android.os.Bundle

import android.widget.Button

import android.widget.LinearLayout

import androidx.appcompat.app.AppCompatActivity

import com.example.common.QuizData

import com.example.common.SqlHelper

 

 

class QuizCreatorActivity : AppCompatActivity() {

 

    override fun onCreate(savedInstanceState: Bundle?) {

        super.onCreate(savedInstanceState)

        setContentView(R.layout.activity_quiz_creator)

        onInit();

    }

 

    private fun onInit() : Unit {

 

        //데이터 베이스에 정보가 있는지 찾는다.

        val dbExistCheck:Boolean = false;

        val sqlHelper = SqlHelper(this);

        val db = sqlHelper.readableDatabase;

        val data:List<QuizData> = sqlHelper.getQuizList<QuizData>();

    }

}

하고 싶은 기능은 QuizData Class를 만들어, sqlHelper에서 리플렉션으로 바로 연동하고 싶다.

 

package com.example.common

 

class QuizData: ISqlData {

    public var quizIndex: Int = 0;

    public var quizText:String = "";

    public var quizImage: Array<Byte?> = emptyArray();

 

    public var example1:String = "";

    public var example2:String = "";

    public var example3:String = "";

    public var example4:String = "";

 

    public var correct:Int = 0;

    public var hint:String = "";

    public var score:Int = 0;

    public var time:Int = 0;

}

QuizData.kt

 

package com.example.common

import android.content.Context

import android.database.sqlite.SQLiteDatabase

import android.database.sqlite.SQLiteOpenHelper

import android.util.Log

import java.lang.Exception

import kotlin.reflect.KClass

 

class SqlHelper(context: Context): SQLiteOpenHelper(context, "Quiz"null1) {

 

    //https://developer.android.com/training/data-storage/sqlite

    companion object{

        private const val DATABASE_VERSION  = 1

        private const val DATABASE_NAME = "Quiz.db"

    }

 

    object SqliteContract {

        //Table

        internal const val TABLE_NAME = "QuizTable"

 

        //Column

        internal const val COLUMN_QUIZ_INDEX = "QuizIndex"

        internal const val COLUMN_QUIZ_TEXT = "QuizText"

        internal const val COLUMN_QUIZ_IMAGE = "QuizImage"

 

        internal const val COLUMN_EXAMPLE1 = "Example1"

        internal const val COLUM_NEXAMPLE2 = "Example2"

        internal const val COLUM_NEXAMPLE3 = "Example3"

        internal const val COLUM_NEXAMPLE4 = "Example4"

 

        internal const val COLUMN_CORRECT = "Correct"

        internal const val COLUMN_HINT = "Hint"

        internal const val COLUMN_SCORE = "Score"

        internal const val COLUMN_TIME = "Time"

    }

 

    private val SQL_CREATE_ENTRIES :String = ("Create Table ${SqliteContract.TABLE_NAME}" +

            "(${SqliteContract.COLUMN_QUIZ_INDEX} INTEGER PRIMARY KEY " +

            ", ${SqliteContract.COLUMN_QUIZ_TEXT} TEXT" +

            ", ${SqliteContract.COLUMN_QUIZ_IMAGE} BLOB" +

            ", ${SqliteContract.COLUMN_EXAMPLE1} TEXT" +

            ", ${SqliteContract.COLUM_NEXAMPLE2} TEXT" +

            ", ${SqliteContract.COLUM_NEXAMPLE3} TEXT" +

            ", ${SqliteContract.COLUM_NEXAMPLE4} TEXT" +

            ", ${SqliteContract.COLUMN_CORRECT} INTEGER" +

            ", ${SqliteContract.COLUMN_HINT} TEXT" +

            ", ${SqliteContract.COLUMN_SCORE} INTEGER" +

            ", ${SqliteContract.COLUMN_TIME} INTEGER)");

 

    private val SQL_DELETE_ENTRIES = "DROP TABLE IF EXISTS ${SqliteContract.TABLE_NAME}"

 

    override fun onCreate(db: SQLiteDatabase?) {

        try{

            db!!.execSQL(SQL_CREATE_ENTRIES);

 

            Log.i("in", SQL_CREATE_ENTRIES);

        }

        catch(ex:Exception){

            Log.d("onCreate", ex.message);

        }

    }

 

    override fun onUpgrade(db: SQLiteDatabase?, oldVersion: Int, newVersion: Int) {

        db!!.execSQL(SQL_DELETE_ENTRIES);

        onCreate(db);

    }

 

    override fun onDowngrade(db: SQLiteDatabase, oldVersion: Int, newVersion: Int) {

        onUpgrade(db, oldVersion, newVersion)

    }

 

    //https://kotlinlang.org/docs/reference/generics.html

    //https://blog.kotlin-academy.com/creating-a-random-instance-of-any-class-in-kotlin-b6168655b64a

    //https://kotlinlang.org/docs/reference/reflection.html

    //CRUD

    public inline fun <reified T> getQuizList(): List<T>

        where T : ISqlData {

 

        //작업중.

        try{

            val sqlDataClass: KClass<T> = T::class//T::class.constructors.first { it.parameters.isEmpty() }.call();

            sqlDataClass.constructors;

 

            sqlDataClass.constructors.forEach {

                Log.d("data", it.name);

            }

        }

        catch (ex:Exception){

            Log.d("getQuizList exception", ex.message);

        }

 

        val list: List<T> = listOf<T>();

        return list;

    }

}

데이터베이스가 만들어지는거까진 확인.

 

리플렉션 종속성 추가.

 

인텔리제이에서 데이터베이스가 생성된걸 확인하려면 다음과 같다.

 

 

View -> Tool Windows -> Device File Explorer 메뉴로 들어간 후에 data -> data -> 프로젝트 만들 때, 정의한 패키지로 되어 있다. 나같은 경우 기본값으로 해서 com.example.quiz(패키지 이름을 잘 만들자. -..-).. 이 곳에 database에 파일이 생성된다. 마우스 오른쪽을 누르고 save as로 원하는 경로에 옮겨주면 된다.

 

sqlite gui 툴을 받아 확인했다.

 

https://sqlitebrowser.org/dl/

 

Downloads - DB Browser for SQLite

Windows Our latest release (3.11.2) for Windows: Note - If for any reason the standard Windows release does not work (e.g. gives an error), try a nightly build (below). Nightly builds often fix bugs reported after the last release. 😄 macOS Our latest relea

sqlitebrowser.org

리플렉션을 하기 전에, 데이터를 디버그로 찍어보고 싶은데 하는 툴 사용법을 잘 모르겠다.

C#같은 경우 인터페이스로 상속한 다음에 제네릭 조건으로 걸면 빌드 시에 모든 오류가 잡히는데 코틀린은 아쉬운데로 데이터베이스를 저렇게 읽어와야 할거같은데. 이 부분도 찾아보려면 시간이 더 걸릴듯.