I have an recyclerview adapter whose attribute called timeLeft which means it can count down the time from set time with time now in every single recyclerview item. I want it updated in real time but don't know how. Please help me [Example picture][1] [1]: https://i.stack.imgur.com/8le2s.png Data file
@Parcelize
@Entity(tableName = "task_table")
data class Task(
//id is the PrimaryKey which is auto generated by Android Room Database
@PrimaryKey(autoGenerate = true)
val id: Int,
val date: String,
val content: String,
var timeLeft: String,
var isDone : Boolean
):Parcelable
Dao File
@Dao
interface TaskDao {
// means it will be just ignore if there is a new exactly same task then we're gonna just ignore it
@Insert(onConflict = OnConflictStrategy.IGNORE)
suspend fun addTask(task :Task)
@Delete
suspend fun deleteTask(task : Task)
@Update
suspend fun updateTask(task : Task)
@Query("SELECT * FROM task_table order by timeLeft ASC")
fun readAllData(): LiveData<MutableList<Task>>
}
Repository File
class TaskRepository (private val taskDao : TaskDao){
val readAllData : LiveData<MutableList<Task>> = taskDao.readAllData()
suspend fun addTask(task : Task){
taskDao.addTask(task)
}
suspend fun deleteTask(task : Task)
{
taskDao.deleteTask(task)
}
suspend fun updateTask(task:Task)
{
taskDao.updateTask(task)
}
}
View Model File
class TaskViewModel(application: Application) : AndroidViewModel(application) {
val readAllData: LiveData<MutableList<Task>>
private val repository: TaskRepository
init {
val taskDao = TaskDatabase.getDatabase(application).taskDao()
repository = TaskRepository(taskDao)
readAllData = repository.readAllData
}
fun addTask(task: Task) {
viewModelScope.launch(Dispatchers.IO) {
repository.addTask(task)
}
}
fun updateTask(task: Task) {
viewModelScope.launch(Dispatchers.IO) {
repository.updateTask(task)
}
}
fun deleteTask(task: Task) {
viewModelScope.launch(Dispatchers.IO) {
repository.deleteTask(task)
}
}
}
Recycler View Adapter File
package com.example.superbtodo.fragments.list
import android.annotation.SuppressLint
import android.graphics.Paint
import android.text.style.StrikethroughSpan
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.*
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProvider
import androidx.navigation.findNavController
import androidx.recyclerview.widget.RecyclerView
import com.example.superbtodo.R
import com.example.superbtodo.data.Task
import com.example.superbtodo.viewmodel.TaskViewModel
class ListAdapter() : RecyclerView.Adapter<ListAdapter.ViewHolder>() {
private var tasks = mutableListOf<Task>()
inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
val contentTextView = itemView.findViewById(R.id.contentTxt) as TextView
val timeTextView = itemView.findViewById(R.id.timeTxt) as TextView
val timeLeftTextView = itemView.findViewById(R.id.timeLeftTxt) as TextView
var isDoneCheckBox = itemView.findViewById(R.id.checkBtn) as RadioButton
val taskLayout = itemView.findViewById(R.id.taskLayout) as RelativeLayout
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val itemView =
LayoutInflater.from(parent.context).inflate(R.layout.task_layout, parent, false)
return ViewHolder(itemView)
}
@SuppressLint("ResourceAsColor")
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val currentItem = tasks[position]
holder.contentTextView.text = currentItem.content
holder.timeTextView.text = currentItem.date
holder.timeLeftTextView.text = currentItem.timeLeft
holder.isDoneCheckBox.isChecked = currentItem.isDone
holder.taskLayout.setOnClickListener {
val action =
ListFragmentDirections.actionListFragmentToUpdateTaskDialogFragment(currentItem)
holder.itemView.findNavController().navigate(action)
}
if (holder.isDoneCheckBox.isChecked) {
holder.timeLeftTextView.visibility = View.GONE
holder.contentTextView.apply {
paintFlags = paintFlags or Paint.STRIKE_THRU_TEXT_FLAG
setTextColor(R.color.gone)
}
holder.timeTextView.apply {
paintFlags = paintFlags or Paint.STRIKE_THRU_TEXT_FLAG
setTextColor(R.color.gone)
}
} else {
holder.timeLeftTextView.visibility = View.VISIBLE
holder.contentTextView.apply {
paintFlags = 0
setTextColor(R.color.black)
}
holder.timeTextView.apply {
paintFlags = 0
setTextColor(R.color.black)
}
}
}
override fun getItemCount(): Int {
return tasks.size
}
@SuppressLint("NotifyDataSetChanged")
fun setData(task: MutableList<Task>) {
this.tasks = task as MutableList<Task>
notifyDataSetChanged()
}
enter code here
fun getTaskAt(position: Int): Task {
return tasks[position]
}
}
CodePudding user response:
Repository File
get live data from database in Repository and return to view model
fun getLiveDataOfTask():MutableLiveData<MutableList<Task>> {
return TaskDatabase.getDatabase(application).taskDao().readAllData()
}
Add In View model class
fun getAllDataTask() = repository.readAllData
In Activity
viewModel?.getAllDataTask()?.observe(this) {
//new Data come hear every time when data was change
changeAdapterData()
}
In Adapter
fun updateList(list: MutableList<Task>) {
this.list = list
notifyDataSetChanged()
}
And if you went to update only time in adapter item from save time and current time difference then add below code in adapter and ignore above code
//global variable
private var handler: android.os.Handler? = null
var hourly = SimpleDateFormat("ss") // add your time formate
// in onBindViewHolder
handler = Handler(Looper.getMainLooper())
var periodicUpdate: Runnable? = null
periodicUpdate = Runnable {
try {
holder.holderItemView.textView.text = hourly.format(System.currentTimeMillis())
periodicUpdate?.let { handler?.postDelayed(it, 1000) }
} catch (e: Exception) {
e.printStackTrace()
}
}
handler?.post(periodicUpdate)