I'm trying to build a room database app with Kotlin. Database part is ok. I need to create adapter to show database data in Recyclerview. But I can't use the holder command. I think it might be related to "Kotlinx.Synthetic has been deprecated". I want to introduce textviews id's to adapter. When i try "holder.itemView.id_txt.text = currentItem.id.toString()" it does not recognize "id_txt.text". Can you help with introduce the custom row's textview ids to adapter. Thank you.
User.kt
import androidx.room.Entity
import androidx.room.PrimaryKey
@Entity(tableName = "user_table")
data class User(
@PrimaryKey(autoGenerate = true)
val id: Int,
val firstName: String,
val lastName: String,
val age: String
)
UserDao.kt
import androidx.lifecycle.LiveData
import androidx.room.Dao
import androidx.room.Insert
import androidx.room.OnConflictStrategy
import androidx.room.Query
@Dao
interface UserDao {
@Insert(onConflict = OnConflictStrategy.IGNORE)
suspend fun addUser(user: User)
@Query("SELECT * FROM user_table ORDER BY id ASC")
fun readAllData(): LiveData<List<User>>
}
UserDatabase.kt
import android.content.Context
import androidx.room.Database
import androidx.room.Room
import androidx.room.RoomDatabase
@Database(entities = [User::class], version = 1, exportSchema = false)
abstract class UserDatabase : RoomDatabase() {
abstract fun userDao(): UserDao
companion object {
@Volatile
private var INSTANCE: UserDatabase? = null
fun getDatabase(context: Context): UserDatabase{
val tempInstance = INSTANCE
if(tempInstance != null){
return tempInstance
}
synchronized(this){
val instance = Room.databaseBuilder(
context.applicationContext,
UserDatabase::class.java,
"user_database"
).build()
INSTANCE = instance
return instance
}
}
}
}
UserRepository.kt
import androidx.lifecycle.LiveData
class UserRepository(private val userDao: UserDao) {
val readAllData: LiveData<List<User>> = userDao.readAllData()
suspend fun addUser(user: User){
userDao.addUser(user)
}
}
UserViewModel.kt
import android.app.Application
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.LiveData
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
class UserViewModel(application: Application): AndroidViewModel(application) {
private val readAllData: LiveData<List<User>>
private val repository: UserRepository
init {
val userDao = UserDatabase.getDatabase(application).userDao()
repository = UserRepository(userDao)
readAllData = repository.readAllData
}
fun addUser(user: User){
viewModelScope.launch(Dispatchers.IO) {
repository.addUser(user)
}
}
}
AddFragment.kt
import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.lifecycle.ViewModelProvider
import androidx.navigation.fragment.findNavController
import com.example.basehw.R
import com.example.basehw.data.UserViewModel
import com.example.basehw.databinding.FragmentAddBinding
import android.text.TextUtils
import android.widget.Toast
import com.example.basehw.data.User
class AddFragment : Fragment() {
private lateinit var mUserViewModel: UserViewModel
private var _binding: FragmentAddBinding? = null
private val binding get() = _binding!!
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View {
// Inflate the layout for this fragment
_binding = FragmentAddBinding.inflate(inflater, container, false)
mUserViewModel = ViewModelProvider(this).get(UserViewModel::class.java)
binding.addBtn.setOnClickListener{
insertDataToDatabase()
}
return binding.root
}
private fun insertDataToDatabase() {
val firstName = binding.addFirstNameEt.text.toString()
val lastName = binding.addFirstNameEt.text.toString()
val age = binding.addAgeEt.text.toString()
if(inputCheck(firstName, lastName, age)){
// Create User Object
val user = User(
0,
firstName,
lastName,
age
)
// Add Data to Database
mUserViewModel.addUser(user)
Toast.makeText(requireContext(), "Successfully added!", Toast.LENGTH_LONG).show()
// Navigate Back
findNavController().navigate(R.id.action_addFragment_to_listFragment)
}else{
Toast.makeText(requireContext(), "Please fill out all fields.", Toast.LENGTH_LONG).show()
}
}
override fun onDestroy() {
super.onDestroy()
}
private fun inputCheck(firstName: String, lastName: String, age: String): Boolean{
return !(TextUtils.isEmpty(firstName) && TextUtils.isEmpty(lastName) && age.isEmpty())
}
}
ListFragment.kt
import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.navigation.fragment.findNavController
import com.example.basehw.R
import com.example.basehw.databinding.FragmentListBinding
class ListFragment : Fragment() {
private var _binding: FragmentListBinding? = null
private val binding get() = _binding!!
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View {
// Inflate the layout for this fragment
_binding = FragmentListBinding.inflate(inflater, container, false)
binding.floatingActionButton.setOnClickListener{
findNavController().navigate(R.id.action_listFragment_to_addFragment)
}
return binding.root
}
override fun onDestroyView() {
super.onDestroyView()
}
}
ListAdapter.kt
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import androidx.viewpager2.adapter.FragmentViewHolder
import com.example.basehw.R
import com.example.basehw.data.User
import com.example.basehw.databinding.ActivityMainBinding
import com.example.basehw.databinding.FragmentListBinding
class ListAdapter: RecyclerView.Adapter<ListAdapter.MyViewHolder>() {
private var binding: ActivityMainBinding? = null
private var userList = emptyList<User>()
class MyViewHolder(itemView: View): RecyclerView.ViewHolder(itemView) {}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
return MyViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.custom_row, parent, false))
}
override fun getItemCount(): Int {
return userList.size
}
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
val currentItem = userList[position]
holder.itemView.id_txt.text = currentItem.id.toString()
holder.itemView.firstName_txt.text = currentItem.firstName
holder.itemView.lastName_txt.text = currentItem.lastName
holder.itemView.age_txt.text = currentItem.age.toString()
}
fun setData(user: List<User>){
this.userList = user
notifyDataSetChanged()
}
}
custom_row.xml
<androidx.constraintlayout.widget.ConstraintLayout 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="wrap_content"
android:id="@+id/custom_row"
android:padding="24sp">
<TextView
android:id="@+id/id_txt"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/_1"
android:textSize="40sp"
android:textStyle="bold"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/firstName_txt"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="80dp"
android:text="@string/john"
android:textSize="24sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toEndOf="@+id/id_txt"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/lastName_txt"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:text="@string/dao"
android:textSize="24sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toEndOf="@+id/firstName_txt"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/age_txt"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:textSize="24sp"
android:text="@string/_25"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toEndOf="@+id/lastName_txt"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
fragment_list.xml
<androidx.constraintlayout.widget.ConstraintLayout 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"
tools:context=".fragments.list.ListFragment">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerview"
android:layout_width="409dp"
android:layout_height="729dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/floatingActionButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="24dp"
android:layout_marginBottom="24dp"
android:clickable="true"
android:focusable="true"
android:tint="@color/white"
android:src="@drawable/ic_add"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
tools:ignore="SpeakableTextPresentCheck" />
</androidx.constraintlayout.widget.ConstraintLayout>
