Open In App

Android SearchView in Room Database

Improve
Improve
Like Article
Like
Save
Share
Report

SearchView in databases is a pretty basic functionality that you can see in most of the applications in your day-to-day life, then why not, you should learn and implement it. it is not too much complicated to implement in your application. There are a lot of easier ways that are how you can implement it. The tasks that you should use to implement for implementing searchView in-app are:-

  1. You need to create a menu item setting actionViewClass to SearchView and set other action view attributes
  2. Then inflate the menu in the onCreateOptionsMenu() method of the action where you want the search feature.
  3. Then get the SearchView object from the menu and add SearchView.OnQueryTextListener to it by calling setOnQueryTextListener method.
  4. SearchView.OnQueryTextListener has two callback methods onQueryTextSubmit and onQueryTextChange
  5. Method onQueryTextSubmit gets called when the user submits a search by hitting enter button or clicking submit button on the search widget.

In this method, database search can be performed using the text entered into the search view widget. You can enable the search button in the search view widget by calling the setSubmitButtonEnabled method and passing the boolean value of true. it’s a basic idea that how it works. But we are going to discuss the most efficient way for searching data from the room database, for that, you should know about some concepts like:

Prerequisites: 

We are not going to create an app from scratch apart from that, we are providing the source code for initial things like 

  • Updating data in RecyclerView by database
  • Using dependency injection
  • and created some extra classes as well

We are giving you a quick overview of the project, then you will understand it very easily. Download the project by Click Here.

Step by Step Implementation

Step 1: Download the project from GitHub and Add it to your android studio

We hope you all know that how to import existing projects to the android studio if don’t then go to file > open > select downloaded project > then wait… for finish project build

Step 2: build.Gradle files

Navigate to the app > Gradle Scripts > build.Gradle file and add the below dependencies in the dependencies section.

  • We have added some dependencies and plugins
  • and enable view binding
plugins {
   id 'com.android.application'
   id 'kotlin-android'
   id 'kotlin-kapt'     // dagger hilt plugin 
   id 'dagger.hilt.android.plugin'
}

android {

   compileSdkVersion 30
   buildToolsVersion "30.0.2"
   defaultConfig {
       applicationId "com.example.searchViewInRoom"
       minSdkVersion 21
       targetSdkVersion 30
       versionCode 1
       versionName "1.0"
       testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
   }

   // here we have enabled viewBinding
   buildFeatures {
       viewBinding true
   }

   buildTypes {
       release {
           minifyEnabled false
           proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
       }
   }

   compileOptions {
       sourceCompatibility JavaVersion.VERSION_1_8
       targetCompatibility JavaVersion.VERSION_1_8
   }

   kotlinOptions {
       jvmTarget = '1.8'
   }

}

dependencies {
   implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
   implementation 'androidx.core:core-ktx:1.3.2'
   implementation 'androidx.appcompat:appcompat:1.2.0'
   implementation 'com.google.android.material:material:1.2.1'
   implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
   testImplementation 'junit:junit:4.13.1'
   androidTestImplementation 'androidx.test.ext:junit:1.1.2'
   androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'

   // Navigation Component
   implementation 'androidx.navigation:navigation-fragment-ktx:2.3.2'

   // Room components
   implementation "androidx.room:room-runtime:2.2.6"

   kapt "androidx.room:room-compiler:2.2.6"
   implementation "androidx.room:room-ktx:2.2.6"

   androidTestImplementation "androidx.room:room-testing:2.2.6"

   // Dagger - Hilt
   implementation "com.google.dagger:hilt-android:2.28.3-alpha"

   kapt "com.google.dagger:hilt-android-compiler:2.28.3-alpha"
   implementation "androidx.hilt:hilt-lifecycle-viewmodel:1.0.0-alpha02"
   kapt "androidx.hilt:hilt-compiler:1.0.0-alpha02"

   // Lifecycle
   implementation "androidx.lifecycle:lifecycle-extensions:2.2.0"
   implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0"
   implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.2.0"
}

Step 3: Creating Entity/Table

Go to app > main > searchViewInRoom > data > person.kt. This is how we can create an entity/table in SQLite database using room

Kotlin




package com.example.searchViewInRoom.data
  
import androidx.room.Entity
import androidx.room.PrimaryKey
  
// it's our data class that we have
// annotate @Entity to create it as table
@Entity(tableName = "person_table")
data class Person(
    // table is basically 
      // having 3 fields as follow....
    var firstName: String,
    var lastName: String,
    var age: Int
){
    @PrimaryKey(autoGenerate = true)
    // we make id as primary 
      // key and it will autogenerate
    var id: Int = 0
}


Step 4: Create a database 

Go to app > main > searchViewInRoom>data > personDatabase.kt. This is how you can create a database. Please read the comments for a better understanding.

Kotlin




package com.example.searchViewInRoom.data
  
import androidx.room.Database
import androidx.room.RoomDatabase
// it's our database and here we 
// specify entities, our version and exportSchema
@Database(
    entities = [Person::class],
    version = 1,
    exportSchema = false
)
// in our database we have just extended RoomDatabase class
abstract class PersonDatabase: RoomDatabase() {
    // as you can see it is our abstract fun and 
    // it represent our Data Access Object (dao)
    abstract fun personDao(): PersonDao
}


Step 5: Database module class

Go to app > main > searchViewInRoom > di > DatabaseModule.kt. Here we use dependency injection

Kotlin




package com.example.searchViewInRoom.di
  
import android.content.Context
import androidx.room.Room
import com.example.searchViewInRoom.data.PersonDatabase
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.android.components.ApplicationComponent
import dagger.hilt.android.qualifiers.ApplicationContext
import javax.inject.Singleton
  
// this is a very important step actually
// here we used dependency injection library dagger hilt
// it actually provide our database object and dao
  
@Module
@InstallIn(ApplicationComponent::class)
object DatabaseModule {
  
    @Singleton
    @Provides
    fun provideDatabase(
        @ApplicationContext context: Context
    ) = Room.databaseBuilder(
        context,
        PersonDatabase::class.java,
        "person_database"
    ).build()
  
    @Singleton
    @Provides
    fun provideDao(database: PersonDatabase) = database.personDao()
  
}


Step 6: Dao (Data Access Object) Class

Go to app > main > searchViewInRoom>data > personDao.kt

Kotlin




package com.example.searchViewInRoom.data
  
import androidx.room.Dao
import androidx.room.Insert
import androidx.room.OnConflictStrategy
import androidx.room.Query
import kotlinx.coroutines.flow.Flow
  
// here we have our Dao having three
// different queries as follows.....
@Dao
interface PersonDao {
  
    // it's basically for reading our database
    @Query("SELECT * FROM person_table ORDER BY id ASC")
    fun readData(): Flow<List<Person>>
  
    // it's for inserting person object to our database
    @Insert(onConflict = OnConflictStrategy.REPLACE)
    suspend fun insertData(person: Person)
  
    // it's very important one for this article because
    //it's a query for searching our database
    /*
    so here we have written basic sql query for searching our database
    basically will search from our person table or entity
    where our first name and last name contains some characters from our searchquery
     */
    @Query("SELECT * FROM person_table WHERE firstName LIKE :searchQuery OR lastName LIKE :searchQuery")
    // and then search query will be passed through 
    // the perimeter of this function
    // and then function will return the flow of list of person
    fun searchDatabase(searchQuery: String): Flow<List<Person>>
  
}


Step 7: Creating a Repository Class

Go to app > main > searchViewInRoom > data > Repository.kt

Kotlin




package com.example.searchViewInRoom.data
  
import kotlinx.coroutines.flow.Flow
import javax.inject.Inject
// it's repository
  
/*
here we have basically injected our person Dao for our dao interface
and having three function as well........ */
class Repository @Inject constructor(
    private val personDao: PersonDao
) {
  
    fun readData(): Flow<List<Person>> {
        return personDao.readData()
    }
  
    suspend fun insertData(person: Person) {
        personDao.insertData(person)
    }
  
    fun searchDatabase(searchQuery: String): Flow<List<Person>> {
        return personDao.searchDatabase(searchQuery)
    }
  
}


Step 8: MainViewModel

Go to app > main > searchViewInRoom>viewmodel > MainViewModel.kt. We are going to use this module to receive and observe data from the database.

Kotlin




package com.example.searchViewInRoom.viewmodel
  
import androidx.hilt.lifecycle.ViewModelInject
import androidx.lifecycle.LiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.asLiveData
import androidx.lifecycle.viewModelScope
import com.example.searchViewInRoom.data.Person
import com.example.searchViewInRoom.data.Repository
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
  
// here we have our viewModel
  
// and we are going to use it for receiving
// and observing data from our database
class MainViewModel @ViewModelInject constructor(
    private val repository: Repository
) : ViewModel() {
  
    val readData = repository.readData().asLiveData()
  
    fun insertData(person: Person){
        viewModelScope.launch(Dispatchers.IO) {
            repository.insertData(person)
        }
    }
  
    fun searchDatabase(searchQuery: String): LiveData<List<Person>> {
        return repository.searchDatabase(searchQuery).asLiveData()
    }
  
}


These all the classes mentioned above are already in the project that you have downloaded, and it’s a quick overview. Now let’s move to the XML part of the given project …

activity_main.xml file 

Now we have to navigate to app > res > activity_main.xml and Understand the below code.

XML




<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">
    
    <!--recycler view for displaying all data -->
    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recyclerView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.0"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.0"
        tools:listitem="@layout/row_layout">
  
    </androidx.recyclerview.widget.RecyclerView>
    
    <!--fab for adding dummy data -->
    <com.google.android.material.floatingactionbutton.FloatingActionButton
        android:id="@+id/floatingActionButton"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:clickable="true"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.954"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.976"
        android:backgroundTint="#098043"
        app:srcCompat="@android:drawable/ic_input_add"
        tools:ignore="SpeakableTextPresentCheck,ImageContrastCheck"
        android:focusable="true" />
  
</androidx.constraintlayout.widget.ConstraintLayout>


row_layout.xml file

It’s an item view, that we have to add in RecyclerView

XML




<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    app:cardCornerRadius="5dp"
    android:padding="5dp"
    android:layout_margin="5dp"
    app:cardBackgroundColor="#B9F6CA">
  
<RelativeLayout
    android:layout_width="wrap_content"
    android:layout_height="wrap_content">
  
    <TextView
        android:id="@+id/firstName_textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="10dp"
        android:layout_marginTop="10dp"
        android:layout_marginEnd="10dp"
  
        android:layout_marginBottom="10dp"
        android:fontFamily="@font/jockey_one"
        android:text="krish"
        android:textColor="@color/black"
        android:textSize="24sp" />
  
    <TextView
        android:id="@+id/lastName_textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="10dp"
        android:fontFamily="@font/jockey_one"
        android:layout_marginBottom="10dp"
        android:layout_toEndOf="@+id/firstName_textView"
        android:text="moris"
        android:textColor="@color/black"
        android:textSize="24sp" />
  
    <TextView
        android:id="@+id/age_textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentEnd="true"
        android:layout_marginTop="10dp"
        android:layout_marginRight="30dp"
        android:text="20"
        android:textColor="@color/black"
        android:textSize="24sp"
        android:textStyle="bold" />
  
</RelativeLayout>
</androidx.cardview.widget.CardView>


that’s it for the whole project that I have given to you, After that your app should look like this ……

But if the given list is shown then well and good otherwise don’t worry, we will manage it. now let’s start the real part of the article (implementation of SearchView). There are only three steps to implement your search functionality, which are as follows…

  • add search icon anywhere on the screen
  • override onCreateOptionsMenu() method
  • then implement onQueryTextListner in our mainActivity

that’s it. so let’s do them.

Step 1: Add search icon anywhere on the screen

We are adding it at the top right corner of the app. For that, you have to create a menu item, by resource manager > menu > add menu resource file

XML




<?xml version="1.0" encoding="utf-8"?>
  
    <item android:id="@+id/menu_search"
        android:title="@string/search"
        android:icon="@drawable/ic_search"
        android:iconTint="@color/white"
        app:showAsAction="ifRoom"
        app:actionViewClass="androidx.appcompat.widget.SearchView"/>
  
</menu>


Step 2: override onCreateOptionsMenu() method

Go to MainActivity.kt. It has some code already, but read the comments, I mentioned there and you can easily understand it as well.

Kotlin




package com.example.searchViewInRoom
  
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.view.Menu
import android.widget.Toast
import androidx.activity.viewModels
import androidx.appcompat.widget.SearchView
import androidx.recyclerview.widget.LinearLayoutManager
import com.example.searchViewInRoom.adapter.MyAdapter
import com.example.searchViewInRoom.data.Person
import com.example.searchViewInRoom.databinding.ActivityMainBinding
import com.example.searchViewInRoom.viewmodel.MainViewModel
import dagger.hilt.android.AndroidEntryPoint
  
@AndroidEntryPoint
class MainActivity : AppCompatActivity(){
  
    // as you can see this is my main activity and
    // here we have created view binding for binding our views
    private lateinit var binding: ActivityMainBinding
  
    // here we have initialized our mainViewModel
    private val mainViewModel: MainViewModel by viewModels()
      
    // and recycler view adapter
    private val myAdapter: MyAdapter by lazy { MyAdapter() }
  
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)
  
        // here we are using linear layout manager for our recyclerView
        binding.recyclerView.layoutManager = LinearLayoutManager(this)
          
        // here we are setting my recyclerView 
        // to custom adapter that we have already made
        binding.recyclerView.adapter = myAdapter
  
        // here we are observing data by mainViewModel 
        // using readData variable
        mainViewModel.readData.observe(this, {
            // using custom recyclerView adapter we have 
            // set the data to our recycler view
            myAdapter.setData(it)
        })
  
    }
  }


After understanding the above code, just get the override onCreateOptionsMenu()

  • for getting just press ctrl+o and search this function then press enter
  • we have to override this function so that we can add our menu here as shown below.

Kotlin




override fun onCreateOptionsMenu(menu: Menu?): Boolean {
    menuInflater.inflate(R.menu.main_menu, menu)
 
    val search = menu?.findItem(R.id.menu_search)
    val searchView = search?.actionView as? SearchView
    searchView?.isSubmitButtonEnabled = true
      // here you get error but don't worry
    searchView?.setOnQueryTextListener(this
    return true
}


After step 2 your main activity will look like this…

Kotlin




package com.example.searchViewInRoom
  
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.view.Menu
import android.widget.Toast
import androidx.activity.viewModels
import androidx.appcompat.widget.SearchView
import androidx.recyclerview.widget.LinearLayoutManager
import com.example.searchViewInRoom.adapter.MyAdapter
import com.example.searchViewInRoom.data.Person
import com.example.searchViewInRoom.databinding.ActivityMainBinding
import com.example.searchViewInRoom.viewmodel.MainViewModel
import dagger.hilt.android.AndroidEntryPoint
  
@AndroidEntryPoint
class MainActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
  
    // as you can see this is my main activity and
    // here we have created view binding for binding our views
    private lateinit var binding: ActivityMainBinding
  
    // here we have initialized our mainViewModel
    private val mainViewModel: MainViewModel by viewModels()
      
    // and recycler view adapter
    private val myAdapter: MyAdapter by lazy { MyAdapter() }
  
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)
  
        // here we are using linear layout manager for our recyclerView
        binding.recyclerView.layoutManager = LinearLayoutManager(this)
          
        // here we are setting my recyclerView to 
        // custom adapter that i have already made
        binding.recyclerView.adapter = myAdapter
  
        // here we are observing data by mainViewModel 
        // using readData variable
        mainViewModel.readData.observe(this, {
            // using custom recyclerView adapter 
            // we have set the data to our recycler view
            myAdapter.setData(it)
        })
  
    }
    override fun onCreateOptionsMenu(menu: Menu?): Boolean {
        menuInflater.inflate(R.menu.main_menu, menu)
  
        val search = menu?.findItem(R.id.menu_search)
        val searchView = search?.actionView as? SearchView
        searchView?.isSubmitButtonEnabled = true
        searchView?.setOnQueryTextListener(this)
        return true
    }


Step 3: Implement onQueryTextListner in MainActivity.kt

To implement your setOnQueryTextListener in main activity for pass ‘this’ as perimeter

  • for implementation just go above and add, SearchView.OnQueryTextListener after class MainActivity : AppCompatActivity() like…. class MainActivity : AppCompatActivity(), SearchView.OnQueryTextListener
  • after another error will show, just move the cursor on error and press alt+Enter
  • then you will have two functions named onQueryTextChange() , onQueryTextChange()
  • then just implement these two functions as

Kotlin




override fun onQueryTextSubmit(query: String?): Boolean {
       // it will triggered when 
       // we submit the written test
       return true
   }
   // this function will triggered when we 
   // write even a single char in search view
   override fun onQueryTextChange(query: String?): Boolean {
       if(query != null){
           searchDatabase(query)
       }
       return true
   }
   // We have just created this function for searching our database
   private fun searchDatabase(query: String) {
       // %" "% because our custom sql query will require that
       val searchQuery = "%$query%"
 
       mainViewModel.searchDatabase(searchQuery).observe(this, { list ->
           list.let {
               myAdapter.setData(it)
           }
       })


yeah! we have successfully implemented a search feature. you can download the final source code by click here.

Now run your app and see. Is your app showing dummy data in recycler view? if yes then you have done it now you can search for something and it will show you results, 

But if don’t then add some dummy data using some steps as…

  • create a function like “fun additem()” inside your MainActivity.kt class
  • then insert data using mainViewModel.insertData(Person(“string : name”, “string: lastname”, int :age)) as shown below in code
  • now just call additem() function when the floating action button is clicked or however, you want.

Kotlin




fun additem(view: android.view.View) {
    mainViewModel.insertData(Person("Krish", "joshi", 18))
    mainViewModel.insertData(Person("Sukant", "desai", 38))
    mainViewModel.insertData(Person("Anye", "jems", 40))
    mainViewModel.insertData(Person("Geek", "geek", 76))
    mainViewModel.insertData(Person("Alok", "pro", 45))
    mainViewModel.insertData(Person("Kushi", "singh", 34))
    mainViewModel.insertData(Person("Final", "step", 23))
    mainViewModel.insertData(Person("Vidyut", "sharma", 20))
    mainViewModel.insertData(Person("Ankit", "chaudhary", 19))
    mainViewModel.insertData(Person("Abhay", "yadav", 16))
}


  • if you want to insert data using the floating action button
  • then just add this line to your floating action button code

android:onClick=”additem”

That’s it your data will also be shown in your app and now you can also check for search…….finally, the app is working like

Output:



Last Updated : 18 Oct, 2021
Like Article
Save Article
Previous
Next
Share your thoughts in the comments
Similar Reads