kubi
kubi

Reputation: 947

RecyclerView not responding on data change

i have this problem.

I've defined simple activity with RecyclerView and i wan't to add an item on button click. I've defined custom RecyclerView.Adapter just like many examples available on the internet, but the view doesn't respond to the data change (todos are being added to todos list). Could someone please take a look and tell me what am i missing?

MainActivity.kt

class MainActivity : AppCompatActivity() {
    private val addButton: FloatingActionButton by lazy { add_button }
    private val todoView: RecyclerView by lazy { todo_view }
    private val todos = mutableListOf<Todo>()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        setSupportActionBar(toolbar)

        todoView.adapter = TodoRecyclerAdapter(todos)
        todoView.layoutManager = LinearLayoutManager(this)
        addButton.setOnClickListener {
            todos.add(Todo("test", "dasdasdas", "11-12-19"))
        }
    }

    override fun onCreateOptionsMenu(menu: Menu): Boolean {
        menuInflater.inflate(R.menu.menu_main, menu)
        return true
    }

    override fun onOptionsItemSelected(item: MenuItem): Boolean = when (item.itemId) {
        R.id.menu_settings -> true
        else -> super.onOptionsItemSelected(item)
    }
}

TodoRecyclerAdapter.kt

class TodoRecyclerAdapter(private val todos: List<Todo>) : RecyclerView.Adapter<TodoViewHolder>() {

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): TodoViewHolder =
        LayoutInflater
            .from(parent.context)
            .inflate(R.layout.layout_todo_item, parent, false)
            .let { TodoViewHolder(it) }

    override fun onBindViewHolder(viewHolder: TodoViewHolder, position: Int) {
        todos[position].run {
            viewHolder.title.text = title
            viewHolder.dueDate.text = dueDate
        }

        viewHolder.parent.setOnClickListener {
            println("Clicked $position item")
        }
    }

    override fun getItemCount(): Int = todos.size

    inner class TodoViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
        val parent: ConstraintLayout = itemView.findViewById(R.id.todo_item)
        val title: TextView = itemView.findViewById(R.id.todo_title)
        val dueDate: TextView = itemView.findViewById(R.id.todo_due_date)
    }
}

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout
        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=".MainActivity">

    <android.support.design.widget.AppBarLayout
            android:layout_height="wrap_content"
            android:layout_width="match_parent"
            android:theme="@style/AppTheme.AppBarOverlay">
        <android.support.v7.widget.Toolbar
                android:id="@+id/toolbar"
                android:layout_width="match_parent"
                android:layout_height="?attr/actionBarSize"
                android:background="?attr/colorPrimary"
                app:popupTheme="@style/AppTheme.PopupOverlay"/>
    </android.support.design.widget.AppBarLayout>

    <android.support.v7.widget.RecyclerView
            app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent"
            android:layout_marginStart="8dp" android:layout_marginBottom="8dp"
            app:layout_constraintBottom_toBottomOf="parent" android:layout_marginTop="8dp"
            app:layout_constraintTop_toTopOf="parent" android:layout_margin="8dp" android:id="@+id/todo_view"
            android:layout_width="match_parent" android:layout_height="657dp" android:layout_gravity="bottom"/>

    <android.support.design.widget.FloatingActionButton
            android:id="@+id/add_button"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="bottom|end"
            android:layout_margin="@dimen/fab_margin"
            app:srcCompat="@android:drawable/ic_dialog_email"/>
</android.support.design.widget.CoordinatorLayout>

layout_todo_item.xml

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.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:background="@color/todoColor"
                                             android:id="@+id/todo_item">
    <TextView
            android:layout_width="370dp"
            android:layout_height="32dp" android:id="@+id/todo_title"
            android:layout_marginBottom="8dp"
            app:layout_constraintBottom_toTopOf="@+id/todo_due_date" android:layout_marginTop="10dp"
            app:layout_constraintTop_toTopOf="parent" app:layout_constraintStart_toStartOf="parent"
            android:layout_marginStart="8dp" app:layout_constraintEnd_toEndOf="parent" android:layout_marginEnd="8dp"
            android:textSize="18sp" app:layout_constraintHorizontal_bias="0.52"
            app:layout_constraintVertical_bias="1.0" android:text="@tools:sample/cities"/>
    <TextView
            android:layout_width="369dp"
            android:layout_height="21dp" android:id="@+id/todo_due_date"
            app:layout_constraintBottom_toBottomOf="parent" android:layout_marginBottom="6dp"
            android:layout_marginEnd="8dp" app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent" android:layout_marginStart="8dp"
            tools:text="@tools:sample/date/ddmmyy"/>
</android.support.constraint.ConstraintLayout>

Todo is just a simple data class. When i run the app on debug, the TodoRecyclerAdapter methods are not being called at all.

Upvotes: 0

Views: 708

Answers (1)

JustTheHighlights
JustTheHighlights

Reputation: 1723

In your MainActivity you have the following code:

addButton.setOnClickListener {
        todos.add(Todo("test", "dasdasdas", "11-12-19"))
}

This simply adds a Todo to the list of todos. The adapter has already received the list before this change and created the todoView accordingly. In order to update todoView with the updated list, you need to explicitly tell the adapter that the data has changed.

You can do so like this:

addButton.setOnClickListener {
        todos.add(Todo("test", "dasdasdas", "11-12-19"))
        todoView.adapter.notifyDataSetChanged()
}

However, since you're only adding an item to the list, you may want to use
notifyItemInserted(int position) instead.

Upvotes: 2

Related Questions