์ด๋ฒ ์์ ๋ ์๋๋ก์ด๋์ ๊ฐ์ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ธ room์ ํ์ฉํด ๋ฐ์ดํฐ๋ฅผ ์ ์ฅํ๊ณ , ๊ทธ๊ฒ์ recyclerview์ ๋ณด์ด๊ฒ ํ๋ ์์ ๋ฅผ ํด๋ณด๊ฒ ๋ค.
room ์ ์ฌ์ฉํ๊ธฐ ์ํด์๋ ๋จผ์ gradle์ ์ถ๊ฐ๋ฅผ ํด์ค์ผ ํ๋ค.
build.gradle(app)
plugins {
id 'kotlin-kapt'
...
}
android {
...
}
dependencies {
implementation "androidx.room:room-runtime:2.4.2"
kapt "androidx.room:room-compiler:2.4.2"
}
์ถ๊ฐ๋ฅผ ํ๊ณ ๋์, ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ๋ค์ด๊ฐ ๋ฐ์ดํฐ๋ค์ ๋ง๋ค์ค์ผ ํ๋ค.
1. ๋ฐ์ดํฐ๋ฒ ์ด์ค ๊ฐ์ฒด ํด๋์ค ์์ฑ
@Entity(tableName = "chat_table")
class ChatEntity(
@PrimaryKey(autoGenerate = true) var uid: Long,
@ColumnInfo(name = "sendId") var sendId: String, // ๋ณด๋ธ ์ฌ๋์ id
@ColumnInfo(name = "comment") var comment: String, // ๋ณด๋ธ ๊ธ
@ColumnInfo(name = "sendTime") var sendTime: String // ๋ณด๋ธ ์๊ฐ
) {
constructor(): this(0, "", "", "00:00")
}
- class์ @Entity ์ด๋ ธํ ์ด์ ์ ๋ถ์ฌ ๊ฐ์ฒด ํด๋์ค๋ผ๋ ๊ฒ์ ์๋ ค์ค๋ค.
- @PrimaryKey๋ ๊ธฐ๋ณธ ํค ๊ฐ์ ๊ฐ๋ ์ผ๋ก, ๋ฌด์กฐ๊ฑด ์์ด์ผ ํ๋ค.
- autoGenerate๋ ๊ธฐ๋ณธํค ์๋ ์์ฑ ์ฌ๋ถ๋ฅผ ๋ํ๋ธ๋ค.(true๋ ์๋ ์์ฑ)
- @ColumnInfo ์ด๋ ธํ ์ด์ ์ ์ฌ์ฉํด์ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ๋ค์ด๊ฐ ์์ดํ ๋ค์ ์ง์ ํด์ค๋ค.
- constructor ๋ถ๋ถ์ default ๊ฐ์ ๋ํ๋ธ๋ค.
2. Data Access Object(DAO) ๋ง๋ค๊ธฐ
DAO๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์ฟผ๋ฆฌ๊ฐ ์๋ ๊ณณ์ผ๋ก ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์ ๊ทผํ ์ ์๋ ๋ฉ์๋๋ค์ ์ ์ํด ๋๋ ๊ณณ์ด๋ค.(๊ธฐ๋ณธ์ ์ธ sql ์ง์์ด ํ์ํ๋ค)
@Dao
interface UserDao {
// ๊ฒ์ ์ฟผ๋ฆฌ
@Query("SELECT * FROM user_table")
fun getAll(): List<UserEntity>
// ์ฝ์
์ฟผ๋ฆฌ
@Insert(onConflict = REPLACE)
fun insert(userEntity: UserEntity)
// ํน์ ๋ฐ์ดํฐ ์ญ์ ์ฟผ๋ฆฌ
@Query("DELETE from user_table WHERE id = :id")
fun deleteAll(id: String)
}
- ๋จผ์ interface์ @Dao ์ด๋ ธํ ์ด์ ์ ๋ถ์ฌ Dao ํด๋์ค๋ผ๋ ๊ฒ์ ์๋ฆฐ๋ค.
- @Query, @Insert ์ด๋ ธํ ์ด์ ์์ sql ๋ฌธ๋ฒ์ ์ฌ์ฉํด์ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์ ๊ทผํ ์ ์๋ค.
- onConflict ๋ถ๋ถ์ ์ค๋ณต๋ ๊ธฐ๋ณธ ํค ๊ฐ์ด ์กด์ฌํ ๊ฒฝ์ฐ ์ต๊ทผ์ ๊ฒ์ผ๋ก ๊ต์ฒดํ๋ ๊ธฐ๋ฅ์ด๋ค.
์๋ฅผ ๋ค์ด, ํ ์ด๋ธ ํ๋๊ฐ ์๋ค๊ณ ์น์.
id(๊ธฐ๋ณธ ํค) | name | pw |
user1 | ditntlro | 1234 |
user2 | rotntldl | 4321 |
id๊ฐ ๊ธฐ๋ณธ ํค์ผ๋, id๊ฐ user1์ธ ์๋ก์ด ๋ฐ์ดํฐ๊ฐ ๋ค์ด์๋ค.
user1 | orltntid | 1111 |
๊ธฐ๋ณธ ํค์ธ id๊ฐ ์ค๋ณต๋๋ฏ๋ก ๊ธฐ์กด์ ๋ฐ์ดํฐ์ธ ditntlro๊ฐ ์ ๊ฑฐ๋๊ณ , ์๋ก ๋ค์ด์จ orltntid๊ฐ ๋ค์ด์จ๋ค.
๊ฒฐ๊ณผ ํ ์ด๋ธ
id | name | pw |
user1 | orltntid | 1111 |
user2 | rotntldl | 4321 |
3. ๋ฐ์ดํฐ๋ฒ ์ด์ค ๋น๋ ๋ง๋ค๊ธฐ
๋ฐ์ดํฐ๋ฒ ์ด์ค ๋น๋๋ ์ฌ์ฉ์๊ฐ room์ ์ํ์ํค๋ ค๋ฉด ์์ด์ผ ํ๋ ๊ณณ์ด๋ค.
@Database(entities = [ChatEntity::class], version = 1)
abstract class ChatDbBuilder: RoomDatabase() {
abstract fun chatDao(): ChatDao
companion object {
private var INSTANCE: ChatDbBuilder? = null
fun getInstance(context: Context): ChatDbBuilder? {
if (INSTANCE == null) {
synchronized(ChatDbBuilder::class.java) {
INSTANCE = Room.databaseBuilder(context.applicationContext,
ChatDbBuilder::class.java, "chat_table")
.fallbackToDestructiveMigration()
.build()
}
}
return INSTANCE
}
}
}
- @Database ์ด๋ ธํ ์ด์ ์ ์ฌ์ฉํด์ ๊ทธ ์์ ์์ ์ด ๋ง๋ entity ํด๋์ค๋ฅผ ๋ฌ์์ฃผ๊ณ , ๋ฒ์ ๋ ์ค์ ํด์ค๋ค.
- ์ถ์ ํด๋์ค๋ก ๋ง๋ค๊ณ , ์ถ์ ํด๋์ค์ด๊ธฐ ๋๋ฌธ์ ์ถ์ ๋ฉ์๋ chatDao๋ฅผ ๋ง๋ค์๋ค.
- companion object ์์๋ค๊ฐ ๋ฐ์ดํฐ๋ฒ ์ด์ค ๋น๋๋ฅผ ์ค์ ํด์ค๋ค.
4. Recyclerview ๊ตฌํ
room ๊ธฐ๋ฅ ๊ตฌํ์ด ๋๋ฌ์ผ๋ฏ๋ก, ์ด์ ๋ recyclerView๋ฅผ ์ฌ์ฉํด์ผ ํ๋ค.
recyclerview์ ๋ํด ์ ๊ณ ํ ๋งํ ๊ฒ๋ค
https://yunaaaas.tistory.com/43
recyclerview item xml ํ์ผ
<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:layout_margin="10dp"
app:cardCornerRadius="10dp">
<LinearLayout
android:background="#FFF9C4"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal">
<de.hdodenhof.circleimageview.CircleImageView
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_marginStart="10dp"
android:layout_marginTop="10dp"
android:layout_marginEnd="15dp"
android:src="@drawable/ic_baseline_account_circle_24"/>
<TextView
android:id="@+id/recycler_view_item_id"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="username"
android:layout_marginTop="5dp"
android:layout_gravity="center"
android:textSize="20sp"
android:fontFamily="@font/sunflower_light"/>
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="15dp"
android:orientation="horizontal">
<TextView
android:id="@+id/recycler_view_item_comment"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="comment"
android:textSize="25sp"
android:background="#FFF6A5"
android:layout_marginEnd="10dp"/>
<TextView
android:id="@+id/recycler_view_item_time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="time"
android:textSize="20sp"/>
</LinearLayout>
</LinearLayout>
</androidx.cardview.widget.CardView>
RecyclerView Adapter ํด๋์ค
class ChattingRecyclerAdapter(val context: Context, var chatList: List<ChatEntity>)
: RecyclerView.Adapter<ChattingRecyclerAdapter.ViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val binding = RecyclerviewItemChatBinding.inflate(LayoutInflater.from(parent.context), parent, false)
return ViewHolder(binding)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.bind(chatList[position])
}
override fun getItemCount(): Int {
return chatList.size
}
@SuppressLint("NotifyDataSetChanged")
fun setData(chat: List<ChatEntity>) {
chatList = chat
notifyDataSetChanged()
}
inner class ViewHolder(val binding: RecyclerviewItemChatBinding): RecyclerView.ViewHolder(binding.root) {
val id = binding.recyclerViewItemId
val comment = binding.recyclerViewItemComment
val time = binding.recyclerViewItemTime
fun bind(chatEntity: ChatEntity) {
id.text = chatEntity.sendId
comment.text = chatEntity.comment
time.text = chatEntity.sendTime
}
}
}
์ด๋ํฐ์๋ view binding์ ์ฌ์ฉํด ๋ณด์๋ค.
5. Activity ๊ตฌํ
recyclerview ๊ตฌํ๋ ๋ง์ณค์ผ๋, ์ด์ ๋ ์กํฐ๋นํฐ ๊ตฌํ์ ํ ์ฐจ๋ก์ด๋ค.
room, recyclerview ์์ฑ
val r = Runnable {
try {
chatList = chatDb.chatDao().getAll()
adapter = ChattingRecyclerAdapter(this, chatList)
adapter.notifyDataSetChanged()
recyclerView = binding.chatRecyclerView
recyclerView.adapter = adapter
recyclerView.layoutManager = LinearLayoutManager(this)
recyclerView.setHasFixedSize(true)
} catch (e: Exception) {
Log.e("ERROR", "$e")
}
}
room๊ณผ recyclerview๋ฅผ ์์ฑํ ๋, Thread ์์๋ค๊ฐ ๋ง๋ค์ด ์ฃผ์๋ค.
๋ฐ์ดํฐ๋ฅผ ์ฝ์ ํ๋ ์ฝ๋
val addRunnable = Runnable {
val newChat = ChatEntity()
// TODO :: intent ๊ฐ ๋ฐ์์ค๊ธฐ
newChat.sendId = intent.getStringExtra("id").toString()
newChat.comment = binding.chatComment.text.toString()
// ์๊ฐ ๊ตฌํ๊ธฐ
val now = System.currentTimeMillis()
val date = Date(now)
val dateFormat = SimpleDateFormat("MM/dd hh:ss")
val getTime = dateFormat.format(date)
newChat.sendTime = getTime.toString()
chatDb.chatDao().insert(newChat)
}
val addThread = Thread(addRunnable)
addThread.start()
chatEntity์์๋ค๊ฐ ๋ฐ์ดํฐ๋ค์ ๋ฃ์ด์ค ํ, ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์ฝ์ ํด์ค๋ค.
์ ์ฒด ์ฝ๋
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityRoomChatBinding
private lateinit var chatList: List<ChatEntity>
private lateinit var chatDb: ChatDbBuilder
private lateinit var recyclerView: RecyclerView
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityRoomChatBinding.inflate(layoutInflater)
chatDb = ChatDbBuilder.getInstance(this)!!
var adapter: ChattingRecyclerAdapter
binding.chatUserId.text = intent.getStringExtra("id").toString()
Log.d("TAG", "intent putExtra: ${intent.getStringExtra("image")}")
val r = Runnable {
try {
chatList = chatDb.chatDao().getAll()
adapter = ChattingRecyclerAdapter(this, chatList)
adapter.notifyDataSetChanged()
recyclerView = binding.chatRecyclerView
recyclerView.adapter = adapter
recyclerView.layoutManager = LinearLayoutManager(this)
recyclerView.setHasFixedSize(true)
} catch (e: Exception) {
Log.e("ERROR", "$e")
}
}
binding.imageSendComment.setOnClickListener {
if (binding.chatComment.text.isNotEmpty()) {
addData()
} else {
Toast.makeText(this, " ๋น์์ด์", Toast.LENGTH_SHORT).show()
}
}
val thread = Thread(r)
thread.start()
setContentView(binding.root)
}
private fun addData() {
val addRunnable = Runnable {
val newChat = ChatEntity()
// TODO :: intent ๊ฐ ๋ฐ์์ค๊ธฐ
newChat.sendId = intent.getStringExtra("id").toString()
newChat.comment = binding.chatComment.text.toString()
// ์๊ฐ ๊ตฌํ๊ธฐ
val now = System.currentTimeMillis()
val date = Date(now)
val dateFormat = SimpleDateFormat("MM/dd hh:ss")
val getTime = dateFormat.format(date)
newChat.sendTime = getTime.toString()
chatDb.chatDao().insert(newChat)
}
val addThread = Thread(addRunnable)
addThread.start()
}
}
๐ก๋๋ ์
- ์๋ ์๋ ์ด๋ ค์ ๋ room์ ๋ํด ์๋ก์ด ๋ด์ฉ์ ์๊ฒ ๋์๊ณ , ๋ ๋ง์ ๋ด์ฉ์ ์ดํดํ ์ ์์๋ค
- room์ ๊ณต๋ถํ๋ฉด์ sql ๋ฌธ๋ฒ์ ํ์์ฑ(?) ์ ๋๊ผ๋ค.
- ๋ด๊ฐ ์๊ณ ์๋ ๋ด์ฉ์ ์ค๋ช ํ๊ธฐ๊ฐ ์๊ฐ๋ณด๋ค ์ด๋ ค์ ๋ค.
'๐ฑ| Android > ๐ | Jetpack' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[Android, Kotlin] Compose UI ์ ๋ฆฌ(4) (0) | 2022.12.05 |
---|---|
[Android, Kotlin] Compose UI ์ ๋ฆฌ(3) (0) | 2022.12.04 |
[Android, Kotlin] Compose UI ์ ๋ฆฌ(2) (0) | 2022.12.03 |
[Android, Kotlin] Compose UI ์ ๋ฆฌ(1) (0) | 2022.12.01 |
[Android Kotlin] navigation component์ bottom navigation ์ฐ๊ฒฐ ํ์๋, bottom navigation์ด ์๋๋์ง ์์๋ ํด๊ฒฐ ๋ฐฉ๋ฒ (0) | 2022.04.22 |