Logo

dev-resources.site

for different kinds of informations.

Implementing ListView inside RecyclerView and observing LiveData

Published at
9/6/2020
Categories
kotlin
android
mvvm
recyclerview
Author
anureet19
Categories
4 categories in total
kotlin
open
android
open
mvvm
open
recyclerview
open
Author
9 person written this
anureet19
open
Implementing ListView inside RecyclerView and observing LiveData

Recently I wanted to show cards in my application which gets updated according to the month I have added in my list. Inside the card, I wanted to show the list of items that I have added for that month. Being a beginner in android, it took me a long time to figure this out so I decided to write a "how to" post on the same. I will be explaining the main files, complete project is available here.

Let's get started 💁

I have created a simple application as an example

Alt Text

In the above screen, there is an option to add name and a category to which it belongs. For selection of a single category, I have implemented a spinner inside this fragment. On the home page, a card will be generated according to the category added and it will show the name of the category and the respective list of items belonging to that category. Floating action button can be used to add more items to the list.

Alt Text

I have used MVVM architecture and single activity multiple fragments pattern to implement this app. There are two parts to this. One is on adding cards according to the category added to the database and the other one is on how to insert list inside an existing list.

Adding card dynamically

So firstly add recyclerview to your fragment



<androidx.recyclerview.widget.RecyclerView
        android:id="@+id/card_list"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:listitem="@layout/card_item" />


Enter fullscreen mode Exit fullscreen mode

I have created a database to store items which uses data class Favourites.kt

Favourites.kt



import androidx.room.Entity
import androidx.room.PrimaryKey

enum class Categories{
    Movies, Sports, Fruits, Vegetables
}

@Entity(tableName = "favourites")
data class Favourites(@PrimaryKey(autoGenerate = true) val id: Long,
                      val name : String,
                      val category: Int)


Enter fullscreen mode Exit fullscreen mode

FavouritesListDao.kt



import androidx.lifecycle.LiveData
import androidx.room.Dao
import androidx.room.Query

@Dao
interface FavouritesListDao{
    @Query("SELECT f1.category, (SELECT f2.name FROM favourites as f2 WHERE f1.category = f2.category) FROM favourites as f1 GROUP BY category")
    fun getData(): LiveData<List<Category>>

}


Enter fullscreen mode Exit fullscreen mode

The above sqlite query is responsible for displaying cards according to the category inserted. The GROUP BY clause will group the data with respect to category.
This query will fetch data from the database. Following data class is being used to store the results obtained by the above query.



import androidx.room.ColumnInfo
import androidx.room.Relation


data class Category(
    @ColumnInfo(name = "category")
    var category: Int,

    @Relation(parentColumn = "category", entityColumn = "category", entity = Favourites::class)
    val children : List<itemName>
)


Enter fullscreen mode Exit fullscreen mode

The code below denotes that the result stored inside children list will be obtained by a self-join .



@Relation(parentColumn = "category", entityColumn = "category", entity = Favourites::class)


Enter fullscreen mode Exit fullscreen mode

Adding ListView inside RecyclerView



(SELECT f2.name FROM favourites as f2 WHERE f1.category = f2.category)


Enter fullscreen mode Exit fullscreen mode

Results obtained from this query present inside the above sqlite query will be stored inside 'children' list. This will be added to the listView inside cardView.

Here is the itemAdapter class:



class ItemAdapter(val context: Context):
    ListAdapter<Category, ItemAdapter.ViewHolder>(
        DiffCallback()
    ){

    override fun onCreateViewHolder(parent: ViewGroup,
                                    viewType: Int): ViewHolder {
        val itemLayout = LayoutInflater.from(parent.context)
            .inflate(R.layout.card_item, parent, false)

        return ViewHolder(itemLayout)
    }

    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        holder.bind(getItem(position))
    }

    inner class ViewHolder (override val containerView: View) : RecyclerView.ViewHolder(containerView),
        LayoutContainer {

        fun bind(item: Category){
            with(item){
                when(item.category){
                    Categories.Movies.ordinal ->{
                        category_name.text = Categories.Movies.toString()
                    }
                    Categories.Sports.ordinal ->{
                        category_name.text = Categories.Sports.toString()
                    }
                    Categories.Fruits.ordinal ->{
                        category_name.text = Categories.Fruits.toString()
                    }
                    else ->  category_name.text = Categories.Vegetables.toString()
                }

                // Setting up list view
                val list: List<String> = item.children.map { it.name }
                val adapter = ArrayAdapter(context, android.R.layout.simple_list_item_1,list)
                item_list.adapter = adapter

            }
        }
    }
}

class DiffCallback : DiffUtil.ItemCallback<Category>() {
    override fun areItemsTheSame(oldItem: Category, newItem: Category): Boolean {
        return oldItem.category == newItem.category
    }

    override fun areContentsTheSame(oldItem: Category, newItem: Category): Boolean {
        return oldItem == newItem
    }
}


Enter fullscreen mode Exit fullscreen mode

This code segment inside the above code is used to set up listView inside card_item (cardView)



// Setting up list view
val list: List<String> = item.children.map { it.name }
val adapter = ArrayAdapter(context,android.R.layout.simple_list_item_1,list)
                item_list.adapter = adapter


Enter fullscreen mode Exit fullscreen mode

To set-up the recyclerView inside home fragment, add this code



with(card_list){
     layoutManager = LinearLayoutManager(activity)
     adapter = ItemAdapter (requireContext())
}


Enter fullscreen mode Exit fullscreen mode

Observing Live Data

Create a repository class for communication between viewModel and DAO



import android.app.Application
import androidx.lifecycle.LiveData

class FavouritesListRepository(context:Application) {
    private val favouritesListDao: FavouritesListDao = FavouritesDatabase.getDatabase(context).favouritesListDao()

    fun getData(): LiveData<List<Category>> {
        return favouritesListDao.getData()
    }

}


Enter fullscreen mode Exit fullscreen mode

To observe live data, create a viewModel class for home fragment.



class FavouriteListViewModel(application: Application): AndroidViewModel(application) {
    private val repo : FavouritesListRepository = FavouritesListRepository(application)

    val items: LiveData<List<Category>>
        get() = repo.getData()

}


Enter fullscreen mode Exit fullscreen mode

Now observe the data inside items list in home fragment



viewModel.items.observe(viewLifecycleOwner, Observer{
            (card_list.adapter as ItemAdapter).submitList(it)
        })


Enter fullscreen mode Exit fullscreen mode

To checkout how items are getting inserted in the database and the structure of the app, here is the github link from where you can download this project

This is my first post. I hope this is helpful.
Alt Text

recyclerview Article's
25 articles in total
Favicon
How to Avoid Blinking in Android Recycler View
Favicon
Introducing RVTimeTracker - RecyclerView Time Tracker
Favicon
RecyclerView Last Item Extra Bottom Margin
Favicon
RecyclerView pagination scroll listener in Android
Favicon
Mostrando os Pokémon com Coil em Android
Favicon
How to create an Expandable Item in Android RecyclerView?
Favicon
Listener de clique no RecyclerView com Kotlin
Favicon
Cloud Firestore Android example – CRUD Operations with RecyclerView
Favicon
Kotlin Firestore example - CRUD Operations with RecyclerView | Android
Favicon
6 Things You Might Not Know About RecyclerView
Favicon
Implementing ListView inside RecyclerView and observing LiveData
Favicon
The Simplest Recycler EmptyView
Favicon
Learn to make list using RecyclerView
Favicon
ExpandableRecyclerView: Expandable Items With Room Database in Kotlin
Favicon
Generic RecyclerViewAdapter
Favicon
Android RecyclerView StickyHeader without external library
Favicon
Doing Android Long Lists Effectively
Favicon
Android RecyclerView single choice adapter
Favicon
Scrolling... Scrolling... RecyclerView for Android with Kotlin!
Favicon
Small RecyclerView XML feature
Favicon
How to use a RecyclerView to show images from storage
Favicon
RecyclerView - II, adding onClick to list items
Favicon
GKE: Ingress Controllers
Favicon
RecyclerView - I
Favicon
Merge Multiple adapters with MergeAdapter

Featured ones: