Android/Room
${Harvey}
2022. 11. 28. 09:32
2022. 11. 28. 09:32
plugins {
id 'kotlin-kapt'
}
// ROOM
def roomVersion = "2.4.0"
implementation("androidx.room:room-runtime:$roomVersion")
annotationProcessor("androidx.room:room-compiler:$roomVersion")
// To use Kotlin annotation processing tool (kapt)
kapt("androidx.room:room-compiler:$roomVersion")
// Coroutine
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.0")
// ViewModelScope
implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.4.1")
}
class Repository(context: Context) {
val db = TextDataBase.getDatabase(context)
fun getTextList() = db.textDao().getAllData()
fun getWordList() = db.wordDao().getAllData()
fun insertTextData(text: String) = db.textDao().insert(TextEntity(0, text))
fun insertWordData(text: String) = db.wordDao().insert(WordEntity(0, text))
fun deleteTextData() = db.textDao().deleteAllData()
fun deleteWordData() = db.wordDao().deleteAllData()
}
class MainViewModel(application: Application) : AndroidViewModel(application) {
val context = getApplication<Application>().applicationContext
val db = TextDataBase.getDatabase(context)
private var _textList = MutableLiveData<List<TextEntity>>()
val textList : LiveData<List<TextEntity>>
get() = _textList
private var _wordList = MutableLiveData<List<WordEntity>>()
val wordList : LiveData<List<WordEntity>>
get() = _wordList
val repository = Repository(context)
fun getData() = viewModelScope.launch(Dispatchers.IO) {
Log.d("MainViewModel",db.textDao().getAllData().toString())
Log.d("MainViewModel",db.wordDao().getAllData().toString())
_textList.postValue(repository.getTextList())
_wordList.postValue(repository.getWordList())
}
fun insertData(text : String) = viewModelScope.launch(Dispatchers.IO) {
repository.insertTextData(text)
repository.insertWordData(text)
}
fun removeData() = viewModelScope.launch (Dispatchers.IO){
repository.deleteTextData()
repository.deleteWordData()
}
}
Dispatcher.IO에서 사용하기위해 postValue를 사용해주어야함.
MainActivity.kt
// ROOM
// https://developer.android.com/training/data-storage/room?hl=ko
// https://developer.android.com/codelabs/android-room-with-a-view-kotlin?hl=ko#5
// https://developer.android.com/kotlin/coroutines/coroutines-adv?hl=ko
class MainActivity : AppCompatActivity() {
lateinit var viewModel : MainViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
viewModel = ViewModelProvider(this).get(MainViewModel::class.java)
viewModel.getData()
val db = TextDataBase.getDatabase(this)
val inputArea = findViewById<EditText>(R.id.textInputArea)
val insertBtn = findViewById<Button>(R.id.insert)
val getAllBtn = findViewById<Button>(R.id.getData)
val deleteBtn = findViewById<Button>(R.id.delete)
insertBtn.setOnClickListener {
viewModel.insertData(inputArea.text.toString())
inputArea.setText("")
}
val rv = findViewById<RecyclerView>(R.id.rv)
viewModel.textList.observe(this, Observer {
val customAdapter = CustomAdapter(it)
rv.adapter = customAdapter
rv.layoutManager = LinearLayoutManager(this)
})
getAllBtn.setOnClickListener {
viewModel.getData()
}
deleteBtn.setOnClickListener {
viewModel.removeData()
}
}
}
class CustomAdapter(private val dataSet : List<TextEntity>) : RecyclerView.Adapter<CustomAdapter.ViewHolder>(){
class ViewHolder(view: View) : RecyclerView.ViewHolder(view){
val textView : TextView = view.findViewById(R.id.textView)
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CustomAdapter.ViewHolder {
val view = LayoutInflater.from(parent.context).inflate(R.layout.text_row_item,parent,false)
return ViewHolder(view)
}
override fun onBindViewHolder(holder: CustomAdapter.ViewHolder, position: Int) {
holder.textView.text = dataSet[position].text
}
override fun getItemCount(): Int {
return dataSet.size
}
}
@Entity(tableName = "text_table")
data class TextEntity (
@PrimaryKey(autoGenerate = true)
@ColumnInfo(name = "id")
var id : Int,
@ColumnInfo(name = "text")
var text: String
)
@Entity(tableName = "word_table")
data class WordEntity (
@PrimaryKey(autoGenerate = true)
@ColumnInfo(name = "id")
var id : Int,
@ColumnInfo(name = "text")
var text: String
)
@Database(entities = [TextEntity::class, WordEntity::class], version = 2)
abstract class TextDataBase : RoomDatabase(){
abstract fun textDao() : TextDao
abstract fun wordDao() : WordDao
companion object {
@Volatile
private var INSTANCE : TextDataBase? = null
fun getDatabase(
context : Context
) : TextDataBase {
return INSTANCE ?: synchronized(this){
val instance = Room.databaseBuilder(
context.applicationContext,
TextDataBase::class.java,
"text_database"
)
.fallbackToDestructiveMigration()
.build()
INSTANCE = instance
instance
}
}
}
}
@Dao
interface WordDao {
@Query("SELECT * FROM text_table")
fun getAllData() : List<WordEntity>
@Insert(onConflict = OnConflictStrategy.IGNORE)
fun insert(text : WordEntity)
@Query("DELETE FROM word_table")
fun deleteAllData()
}
@Dao
interface TextDao {
@Query("SELECT * FROM text_table")
fun getAllData() : List<TextEntity>
@Insert(onConflict = OnConflictStrategy.IGNORE)
fun insert(text : TextEntity)
@Query("DELETE FROM text_table")
fun deleteAllData()
}
${Harvey}
2022. 11. 22. 18:03
2022. 11. 22. 18:03
build.gradle
plugins {
id 'kotlin-kapt'
}
// ROOM
def roomVersion = "2.4.0"
implementation("androidx.room:room-runtime:$roomVersion")
annotationProcessor("androidx.room:room-compiler:$roomVersion")
// To use Kotlin annotation processing tool (kapt)
kapt("androidx.room:room-compiler:$roomVersion")
// Coroutine
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.0")
// ViewModelScope
implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.4.1")
}
class MainViewModel(application: Application) : AndroidViewModel(application) {
val context = getApplication<Application>().applicationContext
val db = TextDataBase.getDatabase(context)
fun getDate() = viewModelScope.launch(Dispatchers.IO) {
Log.d("MainViewModel",db.textDao().getAllData().toString())
Log.d("MainViewModel",db.wordDao().getAllData().toString())
}
fun insertData(text : String) = viewModelScope.launch(Dispatchers.IO) {
db.textDao().insert(TextEntity(0,text))
db.wordDao().insert(WordEntity(0, text))
}
fun removeData() = viewModelScope.launch (Dispatchers.IO){
db.textDao().deleteAllData()
db.wordDao().deleteAllData()
}
}
class MainActivity : AppCompatActivity() {
lateinit var viewModel : MainViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
viewModel = ViewModelProvider(this).get(MainViewModel::class.java)
viewModel.getDate()
val db = TextDataBase.getDatabase(this)
val inputArea = findViewById<EditText>(R.id.textInputArea)
val insertBtn = findViewById<Button>(R.id.insert)
val getAllBtn = findViewById<Button>(R.id.getData)
val deleteBtn = findViewById<Button>(R.id.delete)
insertBtn.setOnClickListener {
viewModel.insertData(inputArea.text.toString())
inputArea.setText("")
}
getAllBtn.setOnClickListener {
viewModel.getDate()
}
deleteBtn.setOnClickListener {
viewModel.removeData()
}
}
}
@Entity(tableName = "text_table")
data class TextEntity (
@PrimaryKey(autoGenerate = true)
@ColumnInfo(name = "id")
var id : Int,
@ColumnInfo(name = "text")
var text: String
)
@Entity(tableName = "word_table")
data class WordEntity (
@PrimaryKey(autoGenerate = true)
@ColumnInfo(name = "id")
var id : Int,
@ColumnInfo(name = "text")
var text: String
)
@Database(entities = [TextEntity::class, WordEntity::class], version = 2)
abstract class TextDataBase : RoomDatabase(){
abstract fun textDao() : TextDao
abstract fun wordDao() : WordDao
companion object {
@Volatile
private var INSTANCE : TextDataBase? = null
fun getDatabase(
context : Context
) : TextDataBase {
return INSTANCE ?: synchronized(this){
val instance = Room.databaseBuilder(
context.applicationContext,
TextDataBase::class.java,
"text_database"
)
.fallbackToDestructiveMigration()
.build()
INSTANCE = instance
instance
}
}
}
}
@Dao
interface WordDao {
@Query("SELECT * FROM text_table")
fun getAllData() : List<WordEntity>
@Insert(onConflict = OnConflictStrategy.IGNORE)
fun insert(text : WordEntity)
@Query("DELETE FROM word_table")
fun deleteAllData()
}
@Dao
interface TextDao {
@Query("SELECT * FROM text_table")
fun getAllData() : List<TextEntity>
@Insert(onConflict = OnConflictStrategy.IGNORE)
fun insert(text : TextEntity)
@Query("DELETE FROM text_table")
fun deleteAllData()
}
${Harvey}
2022. 11. 22. 18:01
2022. 11. 22. 18:01
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val db = TextDataBase.getDatabase(this)
val inputArea = findViewById<EditText>(R.id.textInputArea)
val insertBtn = findViewById<Button>(R.id.insert)
val getAllBtn = findViewById<Button>(R.id.getData)
val deleteBtn = findViewById<Button>(R.id.delete)
insertBtn.setOnClickListener {
CoroutineScope(Dispatchers.IO).launch {
db.textDao().insert(TextEntity(0, inputArea.text.toString()))
db.wordDao().insert(WordEntity(0, inputArea.text.toString()))
inputArea.setText("")
}
}
getAllBtn.setOnClickListener {
CoroutineScope(Dispatchers.IO).launch {
Log.d("MAINACTIVITY", db.textDao().getAllData().toString())
Log.d("MAINACTIVITY", db.wordDao().getAllData().toString())
}
}
deleteBtn.setOnClickListener {
CoroutineScope(Dispatchers.IO).launch {
db.textDao().deleteAllData()
db.wordDao().deleteAllData()
}
}
}
}
@Entity(tableName = "text_table")
data class TextEntity (
@PrimaryKey(autoGenerate = true)
@ColumnInfo(name = "id")
var id : Int,
@ColumnInfo(name = "text")
var text: String
)
@Entity(tableName = "word_table")
data class WordEntity (
@PrimaryKey(autoGenerate = true)
@ColumnInfo(name = "id")
var id : Int,
@ColumnInfo(name = "text")
var text: String
)
@Database(entities = [TextEntity::class, WordEntity::class], version = 2)
abstract class TextDataBase : RoomDatabase(){
abstract fun textDao() : TextDao
abstract fun wordDao() : WordDao
companion object {
@Volatile
private var INSTANCE : TextDataBase? = null
fun getDatabase(
context : Context
) : TextDataBase {
return INSTANCE ?: synchronized(this){
val instance = Room.databaseBuilder(
context.applicationContext,
TextDataBase::class.java,
"text_database"
)
.fallbackToDestructiveMigration()
.build()
INSTANCE = instance
instance
}
}
}
}
@Dao
interface WordDao {
@Query("SELECT * FROM text_table")
fun getAllData() : List<WordEntity>
@Insert(onConflict = OnConflictStrategy.IGNORE)
fun insert(text : WordEntity)
@Query("DELETE FROM word_table")
fun deleteAllData()
}
@Dao
interface TextDao {
@Query("SELECT * FROM text_table")
fun getAllData() : List<TextEntity>
@Insert(onConflict = OnConflictStrategy.IGNORE)
fun insert(text : TextEntity)
@Query("DELETE FROM text_table")
fun deleteAllData()
}
${Harvey}
2022. 11. 22. 18:00
2022. 11. 22. 18:00
Room은 AAC(Android Architecture Components), 스마트폰 내장 DB에 데이터를 저장하기 쉽도록 해주는 라이브러리이다.(DB데이터를 Java or Kotlin 객체로 매핑 해준다.)
다양한 Annotation을 통해서 컴파일시 코드들을 자동 생성 해주고 SQLite와 달리 LiveData, RxJava와 같은 Obervation 형태를 지원 하고 MVP,MVVM과 같은 아키텍쳐 패턴에 쉽게 활용할 수 있도록 되어있다.
Room 라이브러리의 엔티티(Entity), 데이터 접근 객체(DAO),데이터 베이스(DB)의 상세 설명과 사용법은 구글 공식 문서에도 나와있지만 아래 블로그에서 많이 참고하였다.
https://velog.io/@ryalya/Android-DB-Room이란
plugins {
id 'kotlin-kapt'
}
// ROOM
def roomVersion = "2.4.0"
implementation("androidx.room:room-runtime:$roomVersion")
annotationProcessor("androidx.room:room-compiler:$roomVersion")
// To use Kotlin annotation processing tool (kapt)
kapt("androidx.room:room-compiler:$roomVersion")
// Coroutine, Room을 사용 할때 Coroutine을 사용해야함.
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.0")
// https://developer.android.com/training/data-storage/room?hl=ko
// https://developer.android.com/codelabs/android-room-with-a-view-kotlin?hl=ko#5
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val db = TextDataBase.getDatabase(this)
val inputArea = findViewById<EditText>(R.id.textInputArea)
val insertBtn = findViewById<Button>(R.id.insert)
val getAllBtn = findViewById<Button>(R.id.getData)
val deleteBtn = findViewById<Button>(R.id.delete)
insertBtn.setOnClickListener {
CoroutineScope(Dispatchers.IO).launch {
db.textDao().insert(TextEntity(0, inputArea.text.toString()))
inputArea.setText("")
}
}
getAllBtn.setOnClickListener {
CoroutineScope(Dispatchers.IO).launch {
Log.d("MAINACTIVITY", db.textDao().getAllData().toString())
}
}
deleteBtn.setOnClickListener {
CoroutineScope(Dispatchers.IO).launch {
db.textDao().deleteAllData()
}
}
}
}
@Dao
interface TextDao {
@Query("SELECT * FROM text_table")
fun getAllData() : List<TextEntity>
@Insert(onConflict = OnConflictStrategy.IGNORE)
fun insert(text : TextEntity)
@Query("DELETE FROM text_table")
fun deleteAllData()
}
@Entity(tableName = "text_table")
data class TextEntity (
@PrimaryKey(autoGenerate = true)
@ColumnInfo(name = "id")
var id : Int,
@ColumnInfo(name = "text")
var text: String
)
@Database(entities = [TextEntity::class], version = 1)
abstract class TextDataBase : RoomDatabase(){
abstract fun textDao() : TextDao
companion object {
@Volatile
private var INSTANCE : TextDataBase? = null
fun getDatabase(
context : Context
) : TextDataBase {
return INSTANCE ?: synchronized(this){
val instance = Room.databaseBuilder(
context.applicationContext,
TextDataBase::class.java,
"text_database"
)
.fallbackToDestructiveMigration()
.build()
INSTANCE = instance
instance
}
}
}
}