I want btnTodoDone to show how many tasks are done. So in the adapter I add done items to dones. After that I need to get dones’ size in main activity and set it to the button’s text. But there is always 0 because main activity doesn’t see the changes of this list. It sees only empty mutable list. What to do?
TodoAdapter
package com.bignerdranch.android.taskmaster
import android.graphics.Paint.STRIKE_THRU_TEXT_FLAG
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.CheckBox
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import com.bignerdranch.android.taskmaster.databinding.ItemTodoBinding
class TodoAdapter(
private var todos: MutableList<Todo>, private var dones: MutableList<Todo>
):RecyclerView.Adapter<TodoAdapter.TodoViewHolder>() {
class TodoViewHolder( ItemTodoBinding: ItemTodoBinding): RecyclerView.ViewHolder(ItemTodoBinding.root)
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): TodoViewHolder {
val layoutInflater = LayoutInflater.from(parent.context)
val ItemTodoBinding = ItemTodoBinding.inflate(layoutInflater, parent, false)
return TodoViewHolder(
return TodoViewHolder(ItemTodoBinding)
)
}
private fun toggleStrikeThrough(tvTodoTitle: TextView, isChecked:Boolean){
if(isChecked){
tvTodoTitle.paintFlags = tvTodoTitle.paintFlags or STRIKE_THRU_TEXT_FLAG
}else{
tvTodoTitle.paintFlags = tvTodoTitle.paintFlags and STRIKE_THRU_TEXT_FLAG.inv()
}
}
override fun onBindViewHolder(holder: TodoViewHolder, position: Int) {
val curTodo = todos[position]
holder.itemView.apply{
val tvTodoTitle = findViewById(R.id.tvTodoTitle) as TextView
val tvTodoDate = findViewById(R.id.tvTodoDate) as TextView
tvTodoTitle.text = curTodo.title
tvTodoDate.text=curTodo.date
val cbDone = findViewById(R.id.cbDone) as CheckBox
cbDone.isChecked = curTodo.isChecked
toggleStrikeThrough(tvTodoTitle, curTodo.isChecked)
cbDone.setOnCheckedChangeListener { _, isChecked ->
toggleStrikeThrough(tvTodoTitle, isChecked)
curTodo.isChecked = !curTodo.isChecked
}
cbDone.setOnClickListener(View.OnClickListener{
todos.removeAll{todo->
todo.isChecked
}
dones.add(curTodo)
notifyDataSetChanged()
})
}
}
override fun getItemCount(): Int {
return todos.size
}
}
MainActivity
package com.bignerdranch.android.taskmaster
import android.content.Intent
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import androidx.recyclerview.widget.LinearLayoutManager
import com.bignerdranch.android.taskmaster.databinding.ActivityMainBinding
class MainActivity : AppCompatActivity() {
private lateinit var todoAdapter:TodoAdapter
private lateinit var binding: ActivityMainBinding
private var todos: MutableList<Todo> = mutableListOf()
private var dones: MutableList<Todo> = mutableListOf()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
todoAdapter = TodoAdapter(todos, dones)
binding.rvTodoItems.adapter = todoAdapter
binding.rvTodoItems.layoutManager = LinearLayoutManager(this)
binding.btnAddTodo.setOnClickListener{
NewTaskSheet().show(supportFragmentManager,"NewTaskTag")
}
supportFragmentManager.setFragmentResultListener("requestKey",this){ requestKey,bundle ->
val newTodo=bundle.getSerializable("bundleKey") as Todo
todos.add(newTodo)
todoAdapter.notifyDataSetChanged()
}
binding.btnTodoDone.setOnClickListener{
val intent = Intent(this, SecondActivity::class.java)
startActivity(intent)
}
binding.btnTodoDone.text="Done"+"(${dones.size.toString()})"
}
}
2
Answers
make a public method in adapter
and get updated List in Activity by calling this method
This is because you set the button’s text but there is nothing to update the text at every dataSetChange. You will need a persistent value that is notified of it’s changes that has a callback that updates your button text value. You should keep your data as live data in a view model to also make sure your data is not lost durring the activit’s lifecycle.
So you would have something like :
And to make the updates visible , you should pass the VM to your adapter as a param or make your adapter an inner class of MainActivity.
Replace the code in your adapter acordingly :
dones.add(curTodo)
should be nowviewModel.updateDones(curTodo)
And in your MainActivity you must declare and create the view model and set an observer to that livedata: