일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
- WebView
- dart
- 웹뷰
- 유튜브
- 의존성주입
- 안드로이드 스튜디오
- studio
- 에러
- error
- viewpager
- 코틀린
- 안스
- Kotlin
- 스튜디오
- Retrofit
- 레트로핏
- 안드로이드
- Github
- build
- MVVM
- ADB
- Gradle
- Android
- GIT
- image
- 안드로이드스튜디오
- coroutine
- RecyclerView
- 깃헙
- 코루틴
- Today
- Total
코딩하는 일용직 노동자
Room 사용법을 ㅇrㄹr보ㅈr 본문
기존 안드로이드 로컬 데이타베이스를 사용할땐 SQLite를 이용했습니다.
하지만 사용방법이 매우 불편하기 때문에 ORMLite 나 greenDAO 같은 별도의 ORM(Object-relational mapping)을 이용하거나 Realm을 이용합니다.
Room은 SQLite를 편리하게 사용하도록 구글이 공식적으로 내놓은 ORM이라고 생각하시면 됩니다.
(왜 이걸 이제야 내놓는지... 만들어줄거면 진작에 나왔어야 하는거 아닌가 싶으ㄴ... -_-;;)
이번 포스팅에선 Room을 어떻게 사용하는지 기초적인 방법을 확인해보겠습니다.
#1. Room의 기본구성요소
Entity : 데이타베이스의 테이블 이라고 생각하면 됩니다.
DAO(Data Access Object) : 데이타베이스를 조작하는 함수들을 여기서 interface로 정의해줍니다.
Database : 데이타베이스의 진입점입니다. DAO를 반환하는 추상메소드와 사용할 Entity목록을 작성해야 합니다.
#2. gradle
app/build.gradle 에 Room을 사용하기 위한 등록을 합니다.
apply plugin: 'kotlin-kapt'
...
dependencies {
// ROOM 데이타베이스
def room_version = "2.2.5"
implementation "androidx.room:room-runtime:$room_version"
kapt "androidx.room:room-compiler:$room_version" // For Kotlin use kapt instead of annotationProcessor
}
개발환경이 Java인 경우에는 annotationProcessor를, Kotlin인 경우에는 kapt를 사용합니다.
#3. 테이블 만들기
이제 본격적으로 Room을 이용해 데이타베이스를 만들어보도록 하겠습니다.
@Entity 어노테이션을 추가해줍니다.
테이블을 만들기 위해 Room의 구성요소인 Entity를 만듭니다.
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey
/**
* 테이블명을 따로 지정해줄수 있다.
* 만약 지정하지 않는다면 클래스명을 따를것이다.
*/
@Entity(tableName = "user")
data class User(
/**
* 모든 Entity는 PrivaryKey를 하나씩 포함해야 한다.
* autoGenerate 옵션을 추가해서 id를 지정하지 않더라고 자동으로 생성하도록 해준다.
*/
@PrimaryKey(autoGenerate = true)
val id: Int?,
/**
* ColumnInfo는 테이블 내의 스키마를 따로 지정해준다.
*/
@ColumnInfo(name = "name")
val userName: String?,
val age: Int?
)
#4. DAO 만들기
사용할 테이블을 만들었으니 이제 테이블에 접근할 함수들을 만들어줍니다.
@Dao 어노테이션을 추가해줍니다.
import androidx.room.Dao
import androidx.room.Delete
import androidx.room.Insert
import androidx.room.OnConflictStrategy.REPLACE
import androidx.room.Query
@Dao
interface UserDao {
@Query("SELECT * FROM user")
fun getAll(): List<User>
@Query("SELECT * FROM user WHERE id IN (:userIds)")
fun loadAllByIds(userIds: IntArray): List<User>
@Query("SELECT * FROM user WHERE name LIKE :name AND age LIKE :age LIMIT 1")
fun findByNameAndAge(name: String, age: Int): User
/**
* onConflict = REPLACE 만약 같은 내용이 이미 있다면 덮어쓴다는 옵션이다.
*/
@Insert(onConflict = REPLACE)
fun insertUser(user: User)
@Delete
fun deleteUser(user: User)
}
#5. 데이타베이스 만들기
테이블과 DAO를 만들었으니, 이제 데이타베이스를 완성해줍니다.
@Database 어노테이션을 추가해줍니다.
RoomDatabase 를 상속받는 추상클래스로 만듭니다.
entities 에는 사용할 테이블을 지정해줄 수 있습니다. 여러개를 등록할 수 있지만 여기선 User Entity 하나만 등록하겠습니다.
versison 은 버전값입니다. 만약 테이블의 구조가 수정되었다면 이 값을 올려줘야 합니다.
데이타베이스는 싱글턴으로 관리되도록 만들어주겠습니다.
import android.content.Context
import androidx.room.Database
import androidx.room.Room
import androidx.room.RoomDatabase
@Database(entities = arrayOf(User::class), version = 1)
abstract class AppDatabase : RoomDatabase() {
/**
* UserDao를 반환하는 추상화 메소
*/
abstract fun userDao(): UserDao
companion object {
private val DB_NAME = "user-room-db"
/**
* 데이타베이스를 만드는 작업은 리소스를 많이 필요로 한다.
* 때문에 이 프로젝트 내에서 딱 하나만 만들어서 관리하는 것이 유리하다.
* 싱글턴으로 만들도록 한다.
*/
var instance: AppDatabase? = null
fun getInstance(context: Context): AppDatabase? {
if (instance == null) {
synchronized(AppDatabase::class) {
instance = Room.databaseBuilder(
context.applicationContext,
AppDatabase::class.java,
DB_NAME
)
// .fallbackToDestructiveMigration() // Entity의 구조가 바뀌거나 버전이 올라갔을때 기존 내용을 드랍하고 새로 작성하는 옵션.
.build()
}
}
return instance
}
}
}
#6. 테스트 & 결과
AppDatabase 객체 db와 검색 결과를 저장할 User 리스트 객체를 만들고
DAO에 만들어둔 함수들을 호출해서 결과를 확인해보겠습니다.
class MainActivity : AppCompatActivity() {
lateinit var db: AppDatabase
var userList: List<User> = listOf()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
db = AppDatabase.getInstance(this)!!
GlobalScope.launch { // 1
insertDB()
sleep(1000)
findByNameAndAge()
sleep(1000)
loadAllByIds()
sleep(1000)
deleteUser()
}
}
private fun insertDB() {
GlobalScope.launch { // 1
db.userDao().insertUser(User(null, userName = "홍길동", age = 24))
db.userDao().insertUser(User(null, userName = "성춘향", age = 16))
db.userDao().insertUser(User(null, userName = "이몽룡", age = 18))
db.userDao().insertUser(User(null, userName = "소방자", age = 21))
db.userDao().insertUser(User(null, userName = "최향단", age = 17))
userList = db.userDao().getAll()
for (user in userList) {
Log.d("Room", "${user.id} / ${user.userName} / ${user.age}")
}
Log.d("Room", "=======================================")
Log.d("Room", " ")
}
}
private fun findByNameAndAge() {
GlobalScope.launch { // 1
var user = db.userDao().findByNameAndAge(name = "성춘향", age = 16)
Log.d("Room", "${user.id} / ${user.userName} / ${user.age}")
}
Log.d("Room", "=======================================")
Log.d("Room", " ")
}
private fun loadAllByIds() {
GlobalScope.launch { // 1
userList = db.userDao().loadAllByIds(intArrayOf(2, 3, 4))
for (user in userList) {
Log.d("Room", "${user.id} / ${user.userName} / ${user.age}")
}
}
Log.d("Room", "=======================================")
Log.d("Room", " ")
}
private fun deleteUser() {
GlobalScope.launch { // 1
db.userDao().deleteUser(User(null, userName = "소방자", age = 21))
userList = db.userDao().getAll()
for (user in userList) {
Log.d("Room", "${user.id} / ${user.userName} / ${user.age}")
}
}
Log.d("Room", "=======================================")
Log.d("Room", " ")
}
}
github에 프로젝트 파일을 올려놨습니다.
https://github.com/Bacass/MyRoomExam
'안드로이드' 카테고리의 다른 글
Git .gitignore 파일 적용하기. (0) | 2020.09.03 |
---|---|
Bitbucket access denied 해결법 (0) | 2020.09.03 |
Kiel - RecyclerView Adapter Library (0) | 2020.08.04 |
예쁜 Log 라이브러리 Logger (0) | 2020.07.30 |
AsyncTask를 대체할 라이브러리 Needle (0) | 2020.07.30 |