일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- 안드로이드 mvvm 예제
- 디자인 패턴 예제
- dagger error
- 이중for문 사용 안하기
- 아파치란
- apache nginx
- 안드로이드 스튜디오 style
- 안드로이드 스튜디오 인터넷 연결 안되어 있을 때
- 안드로이드 스튜디오 반복되는 레이아웃 코드
- 안드로이드 스튜디오 tts
- 객체지향 프로그래밍 5가지 원칙
- 변수
- java thread 예제
- Kotlin
- 안드로이드 스튜디오 인터넷 연결 확인
- 아파치 엔진엑스
- Thread
- 안드로이드 스튜디오 custom dialog
- recyclerview item recycle
- 안드로이드 디자인패턴
- 안드로이드 스튜디오 커스텀 다이얼로그
- apache란
- LifeCycle
- 리사이클러뷰 아이템 재사용
- AAC
- 자바 스레드 예제
- edittext 연결
- hilt error
- 다른 객체 리스트의 비교
- java
- Today
- Total
Sam Story
룸 (Room) 본문
1. 룸 (Room) 이란 ?
Room은 SQLite의 DB에 편하게 접근할 수 있도록 해주는 AAC에 속한 라이브러리다.
SQLite에 비해 Room을 사용했을 때 얻을 수 있는 이점이 많다.
불필요한 코드들을 줄일 수 있다는 점 그리고
LiveData 등과 함께 사용해 데이터를 Observation 할 수 있다는 점 등 장점이 많다.
현재 Google은 SQLite 대신 Room 사용을 권장하고 있다.
※ SQLite 란 ?
간단하게 말하면 클라이언트 내부에서 사용하는 데이터베이스다.
2. 룸 (Room)의 구성요소
● 데이터베이스 클래스 (AppDatabase)
데이터 베이스를 보유하고 앱의 데이터와 연결해주는 클래스
● 데이터 항목 (Entities)
앱 데이터베이스의 테이블을 나타냄
● 데이터 액세스 객체 (DAO)
앱이 데이터베이스의 데이터를 query , Update , Insert , Delete 를 할 수 있는 메서드를 제공
공식문서에 있는 도식화된 그림으로 살펴보면 아래와 같다.
3. 예제
오늘의 예제는 이름,나이,취미를 리사이클러뷰에 추가해주는 간단한 예제다.
기본적인 SQL 문에 대한 이해도가 필요한 예제이다.
먼저 공식문서에서 가져온 Room 관련 dependency이다.
앱에서 Room을 사용하려면 앱의 build.gradle 파일에 다음 종속 항목을 추가해준다.
dependencies {
def room_version = "2.6.1"
implementation "androidx.room:room-runtime:$room_version"
annotationProcessor "androidx.room:room-compiler:$room_version"
// To use Kotlin annotation processing tool (kapt)
kapt "androidx.room:room-compiler:$room_version"
// To use Kotlin Symbol Processing (KSP)
ksp "androidx.room:room-compiler:$room_version"
// optional - RxJava2 support for Room
implementation "androidx.room:room-rxjava2:$room_version"
// optional - RxJava3 support for Room
implementation "androidx.room:room-rxjava3:$room_version"
// optional - Guava support for Room, including Optional and ListenableFuture
implementation "androidx.room:room-guava:$room_version"
// optional - Test helpers
testImplementation "androidx.room:room-testing:$room_version"
// optional - Paging 3 Integration
implementation "androidx.room:room-paging:$room_version"
}
User 클래스 ( 데이터 항목 (Entities) )
package com.example.room_aac
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey
@Entity
data class User(
@PrimaryKey val num: Int,
@ColumnInfo(name = "name") val name: String?,
@ColumnInfo(name = "age") val age: String?,
@ColumnInfo(name = "hobby") val hobby: String?
)
데이터 클래스로 사용되며 각 칼럼들에 대한 값들이 할당되어 있는 클래스다.
DAO interface
package com.example.room_aac
import androidx.room.Dao
import androidx.room.Delete
import androidx.room.Insert
import androidx.room.Query
@Dao
interface UserDao {
@Query("SELECT * FROM user")
fun getAll(): List<User>
@Query("SELECT * FROM user WHERE num IN (:userIds)")
fun loadAllByIds(userIds: IntArray): List<User>
@Query("SELECT * FROM user WHERE name LIKE :name AND " + "age LIKE :age AND " + "hobby Like :hobby LIMIT 1")
fun findByName(name: String, age: String, hobby: String): User
@Insert
fun insertAll(vararg users: User)
@Delete
fun delete(user: User)
}
DAO 인터페이스에 있는 메서드들에 각각 어노테이션으로 SQL 문을 사용할 수 있다.
데이터 베이스 클래스 (AppDatabase)
package com.example.room_aac
import androidx.room.Database
import androidx.room.RoomDatabase
@Database(entities = [User::class], version = 1)
abstract class AppDatabase: RoomDatabase() {
abstract fun userDao(): UserDao
}
데이터베이스를 보유하고 있는 클래스다
MainActivity
package com.example.room_aac
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.os.Handler
import android.os.Looper
import android.util.Log
import android.widget.Button
import android.widget.EditText
import android.widget.Toast
import androidx.recyclerview.widget.RecyclerView
import androidx.room.Room
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
class MainActivity : AppCompatActivity() {
val TAG = "메인 액티비티"
lateinit var button: Button
lateinit var recyclerView: RecyclerView
lateinit var editTextName: EditText
lateinit var editTextAge: EditText
lateinit var editTextHobby: EditText
lateinit var mAdapter: MAdapter
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
button = findViewById(R.id.button)
recyclerView = findViewById(R.id.recyclerView)
editTextName = findViewById(R.id.editTextName)
editTextAge = findViewById(R.id.editTextAge)
editTextHobby = findViewById(R.id.editTextHobby)
mAdapter = MAdapter()
// Database 초기화
val db = Room.databaseBuilder(
applicationContext,
AppDatabase::class.java, "database-name"
).fallbackToDestructiveMigration()
.build()
// userDao 초기화
val userDao = db.userDao()
// Database 데이터 불러오기
Thread {
var userList = userDao.getAll()
mAdapter.userList.addAll(userList)
recyclerView.adapter = mAdapter
}.start()
button.setOnClickListener {
Thread{
val user = User(mAdapter.userList.size,editTextName.text.toString(),editTextAge.text.toString(),editTextHobby.text.toString())
userDao.insertAll(user)
Handler(Looper.getMainLooper()).post {
mAdapter.userList.add(user)
mAdapter.notifyDataSetChanged()
Toast.makeText(this,"성공적으로 추가했습니다",Toast.LENGTH_SHORT).show()
}
}.start()
}
}
}
메인 액티비티 코드쪽에서 한가지 특이한 점을 볼 수 있는데
데이터베이스 관련 코드들을 메인스레드가 아닌
별도의 스레드를 사용해 코드를 작성하였는데 그이유는
안드로이드에서는 메인 스레드(UI 스레드)에서는
오랜 시간이 걸리는 작업을 수행하지 않도록 권장하고 있다.
따라서 데이터베이스 액세스와 같이 오랜 시간이 걸리는 작업은
백그라운드 스레드에서 처리해야 하기 때문이다.
MainActivity 레이아웃
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="center"
tools:context=".MainActivity">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerView"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_marginHorizontal="10dp">
<EditText
android:id="@+id/editTextName"
android:hint="이름"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<EditText
android:id="@+id/editTextAge"
android:hint="나이"
android:inputType="number"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<EditText
android:id="@+id/editTextHobby"
android:hint="취미"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</LinearLayout>
<Button
android:id="@+id/button"
android:text="추가"
android:layout_margin="20dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>
※ 어댑터 클래스와 아이템뷰 레이아웃은 생략하겠다.
- 깃허브에 어댑터 클래스 코드와 아이템뷰 레이아웃 코드 참고
리사이클러뷰에 대한 내용이 부족하다면
위에 포스팅을 통해 공부해보도록 하자.
위 순서대로 작성하고 코드를 실행해보게 되면
실행결과
최초 실행할 때에는 데이터베이스에 데이터가 없기 때문에
리사이클러뷰에 아무것도 표시되지 않는다.
이제 EditText에 값을 추가한 후 결과를 보자.
추가버튼을 누르게되면 간단한 토스트 메시지와 함께
리사이클러뷰에 아이템이 추가되는걸 볼 수 있다.
이제 데이터가 데이터베이스에 잘 들어갔는지 확인을 위해
앱을 다시 실행시켜보자.
이렇게 내부 데이터베이스에 데이터가 성공적으로 저장되었고
불러올 때도 문제가 없는걸 볼 수 있다.
이러한 룸(Room) 을 사용하게 되면
서버를 거치지 않고도 내부에서도 query문을 사용한 데이터 처리가 가능하고
SharedPreference 보다 좀 더 디테일하게
데이터베이스 테이블을 짜서 데이터를 관리할 수도 있다.
오늘의 예제 github 주소
nam-su/RoomExample: AAC RoomExample (github.com)
'Android' 카테고리의 다른 글
안드로이드 ConstraintLayout (2) | 2024.04.25 |
---|---|
제트팩 컴포즈 (Jetpack Compose) (1) | 2024.04.21 |
라이브 데이터 (LiveData) (0) | 2024.04.13 |
뷰모델 (ViewModel) (0) | 2024.04.11 |
라이프 사이클 (Lifecycle) (1) | 2024.04.02 |