Search code examples
androidkotlinandroid-fragments

Refresh Fragment view when RecyclerView.Adapter is changed


I am following Shrine example application which is implemented in Kotlin part of Google official codelabs for developers. The application and codelab

The last step, We are asked to

Modify your Shrine application to change the product images shown when a category is selected from the backdrop menu.

In the ProductGridFragment#onCreateView I attached a onClick listener on one button to begin with (list of categories, are buttons).

As a test, I just popped an element from the list firstly used in Adapter.

theList = ProductEntry.initProductEntryList(resources)
adapter = StaggeredProductCardRecyclerViewAdapter( theList )

val featured = view.findViewById(R.id.featured) as Button
// set on-click listener
featured.setOnClickListener {
        theList.pop(1)
        adapter.notifyDataSetChanged()

It is not working. Is there other things to do to refresh the view ? all I see in onCreateView seems to be just for first creation of the fragment, I mean, when onClick is produced, it seems to me sufficient to just modify the list and notify adapter on changes.

Do I have to do any thing with view object ?

Any hints ?

Edit 1:

I assigned a new adapter and it works now, this is very nice; Although I do not feel it is performance efficient, as notify for data changes is not really used as intended

featured.setOnClickListener {
    theList = ProductEntry.initProductEntryList(resources, "featured")
    this.adapter = StaggeredProductCardRecyclerViewAdapter(
            theList )
    view.recycler_view.adapter = this.adapter
    this.adapter.notifyDataSetChanged()
}

Solution

  • in Java/Kotlin you always pass by value, not a reference. So when you passed the list to the StaggeredProductCardRecyclerViewAdapter( theList ), you should update the list from Adapter, not the one you passed, so for example:

    class StaggeredProductCardRecyclerViewAdapter(private val theList: List) {
    
        private var listOfItems = theList
    
        fun removeItem(position: Int) {
            listOfItems = listOfItems.remove(position)
            notifyDatasetChanged()
        }
    }
    
    val featured = view.findViewById(R.id.featured) as Button
    // set on-click listener
    featured.setOnClickListener {
           adapter.removeItem(1)
    }
    

    EDIT:

    I went to the codebase and you are operating on the immutable list inside the StaggeredProductCardRecyclerViewAdapter. If you want to filter the items on the list based on "featured" for example, you should do this:

    class StaggeredProductCardRecyclerViewAdapter(private val initList: List<ProductEntry>?) : RecyclerView.Adapter<StaggeredProductCardViewHolder>() {
    
        private var productList: List<ProductEntry>? = initList
    
        override fun getItemViewType(position: Int): Int {
            return position % 3
        }
    
        override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): StaggeredProductCardViewHolder {
            var layoutId = R.layout.shr_staggered_product_card_first
            if (viewType == 1) {
                layoutId = R.layout.shr_staggered_product_card_second
            } else if (viewType == 2) {
                layoutId = R.layout.shr_staggered_product_card_third
            }
    
            val layoutView = LayoutInflater.from(parent.context).inflate(layoutId, parent, false)
            return StaggeredProductCardViewHolder(layoutView)
        }
    
        override fun onBindViewHolder(holder: StaggeredProductCardViewHolder, position: Int) {
            if (productList != null && position < productList.size) {
                val product = productList[position]
                holder.productTitle.text = product.title
                holder.productPrice.text = product.price
                ImageRequester.setImageFromUrl(holder.productImage, product.url)
            }
        }
    
        override fun getItemCount(): Int {
            return productList?.size ?: 0
        }
    
        fun replaceList(items: List<ProductEntry>?) {
            productList = items
            notifyDatasetChanged()
        }
    }
    

    And in ProductGridFragment:

    ...
    featured.setOnClickListener {
           adapter.replaceList(ProductEntry.initProductEntryList(resources, "featured"))
    }