Intro to Android Development
  • Welcome
  • Syllabus
  • Hack Challenge
  • Resources
    • Lecture Videos
    • Ed Discussion
    • Git & GitHub Help/How-To
    • Setting up Android Studio
    • Starting an Android Studio Project & Making an Emulator
    • Importing, Exporting, & Submitting Your Projects to CMS
  • SP25 Course Material
    • Week 1 | Course Logistics, Kotlin, & Basic UI
      • Relevant Links
      • Demo/Lecture: Eatery Card
      • A0: Eatery Card (Follow-Along)
    • Week 2 | States, Components, LazyColumn
      • Relevant Links
      • Demo: Todo List
      • A2: Shopping List
    • Week 3 | Navigation & Animations
      • Relevant Links
      • Demo: Onboarding
      • A3: Stock Trading (RobbingGood)
    • Week 4 | MVVM and Flows
      • Relevant Links
      • Demo: Eatery Card 2
      • A4: Chat of a Lifetime
    • Week 5 | Dumb Components & UIEvents
      • Relevant Links
      • Demo: Music Player
      • A5: Rate My Vibe
    • Week 6 | Coroutines, Networking, JSON
      • Relevant Links
      • Demo: Retrofit
      • A6: You Should Even Lift, Bro.
  • Bonus Week | Android Job Search
    • Relevant Links
    • Android Technical Interview Question!
  • Textbook
    • 1. Introduction to the Editor and Views
      • 1.1 Introduction to the Editor
      • 1.2 SDK Management
      • 1.3 Kotlin Overview
      • 1.4 Views
      • 1.5 Android Studio Project Demo + Understanding The Editor
    • 2. Jetpack Compose
      • 2.1 Introduction
      • 2.2 Layouts
      • 2.3 Modifiers
      • 2.4 Animations
      • 2.5 Lazy Lists
      • 2.6 Reactive UI
    • 3. Intents and Manifest
      • 3.1 Activities
      • 3.2 Implicit Intents
      • 3.3 Explicit Intents
      • 3.4 Manifest
      • 3.5 Permissions
      • 3.6 Summary
    • 4. Navigation
      • 4.1 Types of Navigation
      • 4.2 Implementation of the Bottom Navigation Bar
    • 5. Data and Persistent Storage
      • 5.1 Singleton Classes
      • 5.2 Shared Preferences
      • 5.3 Rooms
      • 5.4 Entities
      • 5.5 Data Access Objects
      • 5.6 Databases
    • 5.5 Concurrency
      • 5.5.1 Coroutines
      • 5.5.2 Implementation of Coroutines
      • 5.5.3 Coroutines with Networking Calls
    • 6. Networking and 3rd Party libraries
      • 6.1 HTTP Overview
      • 6.2 3rd Party Libraries
      • 6.3 JSON and Moshi
      • 6.4 Retrofit
      • 6.5 Summary
    • 7. MVVM Design Pattern
      • 7.1 Key Idea
      • 7.2 Implementation Ideas
    • 8. Flows
    • 9. The Art and Ontology of Software
    • 10. 🔥 Firebase
      • 10.1 Setting up Firebase
      • 10.2 Authentication
      • 10.3 Analytics
      • 10.4 Messaging
      • 10.5 Firestore
  • Additional Topics
    • Git and GitHub
    • Exporting to APK
  • Archive
    • Archived Native Android Textbook Pages
      • 1. Layouts and More Views
        • 1.1 File Structure and File Types
        • 1.2 Resource Files
        • 1.3 Button and Input Control
        • 1.4 ViewGroups
        • 1.5 Summary + A Note On Chapter 2 Topics
      • 2. RecyclerViews
        • 2.1 RecyclerViews
        • 2.2 RecyclerView Performance
        • 2.3 Implementation of a Recycler View
        • 2.4 Implementation with Input Controls
        • 2.5 Filtering RecyclerViews
        • 2.6 Recyclerview Demo
      • 3. ListViews and Searching
        • 3.1 ListView vs. RecyclerView
        • 3.2 ListView Performance
        • 3.3 Implementation of a ListView
        • 3.4 Searching in a List View
      • 4. Fragments
        • 4.1 What are Fragments?
        • 4.2 Lifecycle of a Fragment
        • 4.3 Integrating a Fragment into an Activity
        • 4.4 Sharing Data Between Fragments
        • 4.5 Fragment Slide Shows
      • 5. OkHttp
      • 6. Activity Lifecycle
      • 7. Implementation of Tab Layout
    • Fall 2024 Course Material
      • Lecture 1 & Exercise 1: Introduction to Android
      • Lecture 1.5: Beauty of Kotlin
      • Lecture 2 & HW 2: Modifiers, Lazylists and Reactive UI
      • Lecture 3 & HW 3: Animations, Intents and Manifest
      • Lecture 4 & HW 4: Coroutines & Navigation
      • Lecture 5 & HW 5: Persistent Storage, Networking, and JSON Parsing
      • Lecture 6 & HW 6: MVVM, Flows
      • Bonus Lectures & Bonus HW
      • Bonus Lecture: Industry Practice
    • Spring 2024 Course Material
      • Lecture 1 & Exercise 1: Introduction to Android
      • Lecture 4 & HW 4: LazyLists
      • Lecture 6 & HW 6: Networking, Data, and Persistent Storage
    • Spring 2020 Course Material
      • Week 1: Intro to the Editor
      • Week 2: Views and Layouts
      • Week 3: Intent and Manifest
      • Week 4: ListView and RecyclerView
      • Week 5: Fragments
      • Week 6: Networking
    • Spring 2021 Lecture & HW 8: Networking & 3rd Party APIs
    • HackOurCampus Workshop
Powered by GitBook
On this page
  • Creating a Filter
  • Using the Filter

Was this helpful?

  1. Archive
  2. Archived Native Android Textbook Pages
  3. 2. RecyclerViews

2.5 Filtering RecyclerViews

Creating a Filter

In order to support filtering items in our RecyclerView, we must change a few things. Take our CustomAdapter from 2.3 Implementation of a Recycler View:

class CustomAdapter(private val dataSet: List<Book>) :
        RecyclerView.Adapter<CustomAdapter.ViewHolder>() {

    /**
     * Provide a reference to the type of views that you are using
     * (custom ViewHolder).
     */
    class ViewHolder(view: View) : RecyclerView.ViewHolder(view) {
        val bookName: TextView = view.findViewById(R.id.book_name)
        val author: TextView = view.findViewById(R.id.author)
        val publisher: TextView = view.findViewById(R.id.publisher)
    }

    // Create new views (invoked by the layout manager)
    override fun onCreateViewHolder(viewGroup: ViewGroup, viewType: Int): ViewHolder {
        // Create a new view, which defines the UI of the list item
        val view = LayoutInflater.from(viewGroup.context)
                .inflate(R.layout.book_row_item, viewGroup, false)
        return ViewHolder(view)
    }

    // Replace the contents of a view (invoked by the layout manager)
    override fun onBindViewHolder(viewHolder: ViewHolder, position: Int) {
        // Get element from your dataset at this position and replace the
        // contents of the view with that element
        viewHolder.bookName.text = dataSet[position].bookName
        viewHolder.author.text = dataSet[position].author
        viewHolder.publisher.text = dataSet[position].publisher
    }

    // Return the size of your dataset (invoked by the layout manager)
    override fun getItemCount() = dataSet.size
}

In the RecyclerView adapter, create an ArrayList with the name dataSetFiltered, and pass all the items from our original list. The rest of the adapter is now based off of this filtered list as opposed to the original data set (which should remain unchanged, acting as a source of truth for what an unfiltered list looks like):

class CustomAdapter(private val dataSet: List<Book>) :
        RecyclerView.Adapter<CustomAdapter.ViewHolder>() {
        
     private var dataSetFiltered: List<Book> = dataSet
     
     ...
     
 }  

Return the size of the dataSetFiltered as opposed to the dataSet so the right amount of items to display matches what's filtered:

class CustomAdapter(private val dataSet: List<Book>) :
        RecyclerView.Adapter<CustomAdapter.ViewHolder>() {
        
     private var dataSetFiltered: List<Book> = dataSet
     
     ...
     
     override fun getItemCount(): Int = dataSetFiltered.size
 }  

Now, in the onBindViewHolder get the item for each row from the dataSetFiltered list:

class CustomAdapter(private val dataSet: List<Book>) :
        RecyclerView.Adapter<CustomAdapter.ViewHolder>() {

     private var dataSetFiltered: List<Book> = dataSet
     
     ...
     
     // Replace the contents of a view (invoked by the layout manager)
    override fun onBindViewHolder(viewHolder: ViewHolder, position: Int) {
        // Get element from your dataset at this position and replace the
        // contents of the view with that element
        viewHolder.bookName.text = dataSetFiltered[position].bookName
        viewHolder.author.text = dataSetFiltered[position].author
        viewHolder.publisher.text = dataSetFiltered[position].publisher
    }
     
     override fun getItemCount(): Int = dataSetFiltered.size
}

Lastly, add the capabilities to filter based on some query!

Add the filter variable to your adapter:

class CustomAdapter(private val dataSet: List<Book>) :
        RecyclerView.Adapter<CustomAdapter.ViewHolder>() {

     private var dataSetFiltered: List<Book> = dataSet
     
     var filterTest: CharSequence = ""
        set(value) {
            field = value
            onFilterChange()
        }
     
     ...
     
     // Replace the contents of a view (invoked by the layout manager)
    override fun onBindViewHolder(viewHolder: ViewHolder, position: Int) {
        // Get element from your dataset at this position and replace the
        // contents of the view with that element
        viewHolder.bookName.text = dataSetFiltered[position].bookName
        viewHolder.author.text = dataSetFiltered[position].author
        viewHolder.publisher.text = dataSetFiltered[position].publisher
    }
     
     override fun getItemCount(): Int = dataSetFiltered.size
}

Next, we have to implement onFilterChange:

class CustomAdapter(private val dataSet: List<Book>) :
        RecyclerView.Adapter<CustomAdapter.ViewHolder>() {

     private var dataSetFiltered: List<Book> = dataSet
     
     var filterTest: CharSequence = ""
        set(value) {
            field = value
            onFilterChange()
        }
     
     private fun onFilterChange() {
        dataSetFiltered = if (charString.isEmpty()) {
            // There's no query, should return back the unfiltered list. 
            dataSet 
        } else {
            // The filter function returns a list containing only elements 
            // matching the given predicate. In this case, we can choose 
            // our predicate to be what we want to filter by. Since we are working
            // with books, let's allow filtering by author and title!
            dataSet.filter { book ->
                 book.bookName.contains(charString) || book.author.contains(charString)
            }
        }
        
        notifyDataSetChanged()
     }
     
     // Replace the contents of a view (invoked by the layout manager)
    override fun onBindViewHolder(viewHolder: ViewHolder, position: Int) {
        // Get element from your dataset at this position and replace the
        // contents of the view with that element
        viewHolder.bookName.text = dataSetFiltered[position].bookName
        viewHolder.author.text = dataSetFiltered[position].author
        viewHolder.publisher.text = dataSetFiltered[position].publisher
    }
     
     override fun getItemCount(): Int = dataSetFiltered.size
}

Using the Filter

To use filter, we can simply set the value of the filter in our adapter:

adapter.filter = someText
Previous2.4 Implementation with Input ControlsNext2.6 Recyclerview Demo

Last updated 7 months ago

Was this helpful?

Using notifyDataSetChanged() is costly and often inefficient. We can take advantage of the Android utility class to make updating our RecyclerView more efficient.

We can also leverage to filter our RecyclerView by query from the user.

DiffUtil
SearchView