Learn & Run

Jetpack - Room (1) 본문

Android

Jetpack - Room (1)

iron9462 2021. 7. 14. 23:19

Jetpack에 포함된 Room에 대해 먼저 소개해보려 한다. 이제는 아주 흔하게 들릴지도 모르는 라이브러리지만, 안드로이드 개발을 이제서야 시작한 사람이라면 모를수도 있을 것 이다. 안드로이드 개발자 채용 공고중에 자격 조건을 보면 Jetpack에 포함된 라이브러리들을 사용한 경험이 있는지 여부를 묻기도 한다. 그 만큼 Jetpack은 안드로이드 개발자가 갖춰야할 역량에 있어서 아주 중요한 부분이라고 할 수 있다. 지금까지 SQLite라는 데이터베이스를 공부해오고 있었다면, Room이라는 것을 습득하기에 큰 무리가 없을 것 이다. 다만, 어떤점이 개선 되었고, 차이가 있는지에 대해서라도 알고가야만 할 것 이다. Room을 사용해서 SQLite를 좀 더 안전하고 편리하게 사용할 수 있다고 하는데 한 번 알아보도록 하자.

 

 

Room을 살펴보기전 Jetpack이라는게 무엇인지 궁금할 것 이다. 궁금할 땐 바로 검색해보는 것이 덜찝찝하고 좋다. 아래 사이트에 접속해서 살펴보도록 하자.

 

https://developer.android.com/jetpack?gclid=EAIaIQobChMIkYvy9Nvi8QIVCFpgCh0xLghOEAAYASAAEgKkhvD_BwE&gclsrc=aw.ds 

 

Android 개발자  |  Android Developers

Jetpack은 개발자가 관심 있는 코드에 집중할 수 있도록 권장사항 준수, 상용구 코드 제거, 모든 Android 버전과 기기에서 일관되게 작동하는 코드 작성을 돕는 라이브러리 모음입니다.

developer.android.com

 

 

추가적으로, Jetpack을 알아보면서 Support Library로부터 AndroidX가 나오기까지의 과정들을 아래 당근마켓 블로그를 통해 확인할 수 있다. 나 역시도 새로알 수 있던 부분들이 많고 진지하게 읽었던 블로그이니 참고할 사람은 참고해도 좋다. 아직 모든 것을 이해하기는 어려운 글이지만 변천사에 대해 이유를 알게 되어 신기하기도 하면서 흥미롭다.

 

https://medium.com/daangn/support-library-androidx-그리고-jetifier-항해기-2fb558f56be

 

Support Library, AndroidX 그리고 Jetifier 항해기 👩🏻‍🚀

매년 구글 IO를 관심 있게 지켜보는 안드로이드 개발자로서의 소회라면 이런 것입니다. 트렌드세터가 되고 싶다면 꼭 봐야 할 행사, 덕분에 매년 5월 이후면 할 일 목록이 (제 의지와 상관없이 )

medium.com

 

 

어쨌든, Jetpack이란 것을 살펴보면 아래와 같은 내용을 확인할 수 있다. 앱을 더 빠르고 쉽게 만들 수 있게 도와주는 모음집 이라고 한다. 말로써 백날 읽어봤자 내가 직접 해보지 않으면 모른다. 그러니 코드를 통해서 알아보도록 하자.

 

Android Jetpack은 빠르고 쉽게 훌륭한 Android 앱을 만들 수 있는 컴포넌트, 도구와 아키텍처 안내 세트입니다. 컴포넌트들은 개별적으로 적용 가능하나 Kotlin 언어의 장점을 살려 더 생산성 있도록 함께 작용하도록 설계되었습니다. Jetpack은 백그라운드 태스크, 내비게이션, 그리고 수명주기 관리와 같은 지루한 작업들을 관리해 여러분이 상용구 코드를 없애고 앱에서 강조하는 기능에 집중할 수 있도록 해줍니다. 현대적 설계에 기반하여, Jetpack 컴포넌트는 이전 버전과의 호환 기능이 내장되어 있어 손상 및 메모리 손실을 더 적게 해줍니다.

참고 - https://www.youtube.com/watch?v=LmkKFCfmnhQ

 

SQLite를 직접 사용해보자. 무작정 좋다고 하는 Room을 사용하는 것 보다 비교 대상을 두어 이유를 알게 만드는 것이 좋다고 생각한다. 이전 직장에서 느낀 것 이라면 어떤 생각을 하면서 코드를 구성하는지 나는 말할 수 있어야 한다는 것 이였다. 무튼 아래 코드는 Kotlin으로 작성하였고 간단한 작업만을 보여준다. 그 이유는 Room을 사용하기 앞서 간단하게 사용해보면서 어떤 점이 개선되었으면 좋겠는지, 실제로 Room 라이브러리를 사용하면 개선점이 해결되었는지를 파악하기 위해서이다. 이후에 Room에 대해서 자세하게 설명할 것이다.

 

 

import android.content.ContentValues
import android.content.Context
import android.database.Cursor
import android.database.sqlite.SQLiteDatabase
import android.database.sqlite.SQLiteOpenHelper
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.provider.BaseColumns
import android.util.Log

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val databaseHelper = DatabaseHelper(this, "db.name", null, 1)
        val database = databaseHelper.writableDatabase;

        insert(database)
        select(database)
    }

//ENTRY 테이블에 샘플 데이터를 삽입한다.
    private fun insert(database: SQLiteDatabase) {
        val values = ContentValues().apply {
            put(DatabaseHelper.FeedEntry.COLUMN_NAME_TITLE, "HELLO")
            put(DatabaseHelper.FeedEntry.COLUMN_NAME_SUBTITLE, "WORLD")
        }

        database.insert("ENTRY", null, values)
    }

//ENTRY 테이블에 삽입한 데이터를 로그로 출력한다.
    private fun select(database: SQLiteDatabase) {
        val cursor: Cursor = database.query("ENTRY", null, null, null, null, null, null)
        while (cursor.moveToNext()) {
            Log.e("TITLE : " + cursor.getString(cursor.getColumnIndex("TITLE")),
                    "SUBTITLE : " + cursor.getString(cursor.getColumnIndex("SUBTITLE")))
        }
        cursor.close()
    }
}

//SQLiteOpenHelper를 상속받은 클래스를 정의한다.
class DatabaseHelper(
        context: Context?,
        name: String?,
        factory: SQLiteDatabase.CursorFactory?,
        version: Int
) : SQLiteOpenHelper(context, name, factory, version) {

    object FeedEntry : BaseColumns {
        const val TABLE_NAME = "ENTRY"
        const val COLUMN_NAME_TITLE = "TITLE"
        const val COLUMN_NAME_SUBTITLE = "SUBTITLE"
    }

//클래스가 만들어지는 시점에 테이블을 만들어 준다. 
    override fun onCreate(db: SQLiteDatabase) {
        val sql: String = "CREATE TABLE IF NOT EXISTS ${FeedEntry.TABLE_NAME} (" +
                "${BaseColumns._ID} INTEGER PRIMARY KEY AUTOINCREMENT, " +
                "${FeedEntry.COLUMN_NAME_TITLE} TEXT, " +
                "${FeedEntry.COLUMN_NAME_SUBTITLE} TEXT);"

        db.execSQL(sql)
    }

//버전이 달라지는 시점에 실행되는 콜백메서드이다.
    override fun onUpgrade(db: SQLiteDatabase, oldVersion: Int, newVersion: Int) {
        val sql: String = "DROP TABLE IF EXISTS ${FeedEntry.TABLE_NAME}"

        db.execSQL(sql)
        onCreate(db)
    }
}

 

매우 기본적인 코드기 때문에 위의 코드를 읽기에는 어려움이 없을 것이다. 간단하게나마 SQLite를 사용해보면서 느낀점은 아래와 같다.

 

  • 쿼리를 String으로 처리하는 것이나 Insert, Select 문을 보면 코드가 구시대적인 것 처럼 보이거나 지저분 해 보인다.
  • Schema 및 쿼리가 변경되거나 복잡해질수록 유지보수가 어려울 것 같다. 
  • Schema가 업데이트 될 때 개발자가 직접 버전을 관리해야한다. (개발자는 사람이기 때문에 실수할 여지가 가능성이 있을 수 있다)
  • 결과물을 데이터 클래스로 맵핑해서 데이터를 처리할 수 있으면 더 깔끔한 코드 구성이 가능할 것 같다.

물론 위의 코드는 매우 간단한 코드기 때문에 특히, 안드로이드 개발을 이제야 시작하신 분들에게는 코드에서 느낄 수 있는 문제점들을 찾기 힘들 것이라 생각한다. 이런식의 코드 작성이 무슨 이유가 있어 안좋은지는 설명하기에 굉장히 긴 답변이 될 수 있다. 추상적인 답변이 될 수도 있지만, 개발자들은 프로젝트의 규모가 커지면 커질수록 생길 수 있는 문제점을 미리 해결하고자, 유지보수가 용이한 코드를 만들려고 노력하고 코드가 가지는 위험가능성을 줄이려고 한다. 또한 가독성이 높은 상태를 유지해야 좋은 코드, 성공적인 프로젝트라고 생각할 것 이다. (물론 내 생각이다) 이러한 것 들을 해결하기 위해 나타난 것이 Room이라는 라이브러리이다. 과연 그럴지 추후에 지켜보도록 하자.