Android SearchView en la base de datos de habitaciones

SearchView en bases de datos es una funcionalidad bastante básica que puedes ver en la mayoría de las aplicaciones en tu día a día, entonces por qué no, debes aprenderla e implementarla. no es demasiado complicado de implementar en su aplicación. Hay muchas maneras más fáciles de implementarlo. Las tareas que debe usar para implementar searchView en la aplicación son: –

  1. Debe crear un elemento de menú que configure actionViewClass en SearchView y establecer otros atributos de vista de acción
  2. Luego infle el menú en el método onCreateOptionsMenu() de la acción donde desea la función de búsqueda.
  3. Luego obtenga el objeto SearchView del menú y agréguele SearchView.OnQueryTextListener llamando al método setOnQueryTextListener.
  4. SearchView.OnQueryTextListener tiene dos métodos de devolución de llamada onQueryTextSubmit y onQueryTextChange
  5. Se llama al método onQueryTextSubmit cuando el usuario envía una búsqueda presionando el botón Intro o haciendo clic en el botón Enviar en el widget de búsqueda.

En este método, la búsqueda en la base de datos se puede realizar usando el texto ingresado en el widget de vista de búsqueda. Puede habilitar el botón de búsqueda en el widget de vista de búsqueda llamando al método setSubmitButtonEnabled y pasando el valor booleano de verdadero. es una idea básica de cómo funciona. Pero vamos a discutir la forma más eficiente de buscar datos de la base de datos de la sala, para eso, debe conocer algunos conceptos como:

requisitos previos: 

Aparte de eso, no vamos a crear una aplicación desde cero, estamos proporcionando el código fuente para cosas iniciales como 

  • Actualización de datos en RecyclerView por base de datos
  • Usando la inyección de dependencia
  • y también creó algunas clases adicionales

Le estamos dando una descripción general rápida del proyecto, luego lo entenderá muy fácilmente. Descarga el proyecto haciendo Click Aquí .

Implementación paso a paso

Paso 1: descargue el proyecto de GitHub y agréguelo a su estudio de Android

Esperamos que todos sepan cómo importar proyectos existentes al estudio de Android si no lo hacen, luego vayan a archivo> abrir> seleccione el proyecto descargado> luego espere … para finalizar la construcción del proyecto

Paso 2: compilar archivos Gradle

Vaya a la aplicación > Gradle Scripts > archivo build.Gradle y agregue las siguientes dependencias en la sección de dependencias.

  • Hemos agregado algunas dependencias y complementos.
  • y habilitar el enlace de vista
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"
}

Paso 3: Creación de entidad/tabla

Vaya a aplicación > principal > searchViewInRoom > datos > person.kt. Así es como podemos crear una entidad/tabla en la base de datos SQLite usando la sala

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
}

Paso 4: Crear una base de datos 

Vaya a aplicación > principal > searchViewInRoom>data > personDatabase.kt. Así es como puedes crear una base de datos. Por favor, lea los comentarios para una mejor comprensión.

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
}

Paso 5: clase de módulo de base de datos

Vaya a aplicación > principal > searchViewInRoom > di > DatabaseModule.kt. Aquí usamos la inyección de dependencia

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()
  
}

Paso 6: Clase Dao (objeto de acceso a datos)

Vaya a la aplicación> principal> 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>>
  
}

Paso 7: crear una clase de repositorio

Vaya a la aplicación> principal> searchViewInRoom> datos> 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)
    }
  
}

Paso 8: Modelo de vista principal

Vaya a aplicación > principal > buscarViewInRoom>viewmodel > MainViewModel.kt. Vamos a utilizar este módulo para recibir y observar datos de la base de datos.

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()
    }
  
}

Todas estas clases mencionadas anteriormente ya están en el proyecto que ha descargado, y es una descripción general rápida. Ahora pasemos a la parte XML del proyecto dado…

archivo actividad_principal.xml 

Ahora tenemos que navegar a aplicación > res > actividad_principal.xml y comprender el siguiente código.

XML

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.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="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>

archivo row_layout.xml

Es una vista de elementos, que tenemos que agregar en RecyclerView

XML

<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView
    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"
    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>

eso es todo para todo el proyecto que te he dado. Después de eso, tu aplicación debería verse así

Pero si se muestra la lista dada, muy bien, de lo contrario, no se preocupe, lo administraremos. ahora comencemos la parte real del artículo (implementación de SearchView). S olo hay tres pasos para implementar su función de búsqueda, que son los siguientes…

  • agregar icono de búsqueda en cualquier lugar de la pantalla
  • anular el método onCreateOptionsMenu()
  • luego implemente onQueryTextListner en nuestra actividad principal

eso es todo. así que hagámoslos.

Paso 1: agregue el ícono de búsqueda en cualquier lugar de la pantalla

Lo estamos agregando en la esquina superior derecha de la aplicación. Para eso, debe crear un elemento de menú, mediante administrador de recursos> menú> agregar archivo de recursos de menú

XML

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:tools="http://schemas.android.com/tools"
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">
  
    <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>

Paso 2: invalidar el método onCreateOptionsMenu()

Vaya a MainActivity.kt. Ya tiene algo de código, pero lea los comentarios, lo mencioné allí y también puede entenderlo fácilmente.

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)
        })
  
    }
  }

Después de comprender el código anterior, simplemente obtenga la anulación onCreateOptionsMenu()

  • para obtener solo presione ctrl + o y busque esta función, luego presione enter
  • tenemos que anular esta función para que podamos agregar nuestro menú aquí como se muestra a continuación.

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
}

Después del paso 2, su actividad principal se verá así…

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
    }

Paso 3: implementar onQueryTextListner en MainActivity.kt

Para implementar su setOnQueryTextListener en la actividad principal para pasar ‘esto’ como perímetro

  • para la implementación, simplemente vaya arriba y agregue, SearchView.OnQueryTextListener después de la clase MainActivity: AppCompatActivity() como…. clase MainActivity: AppCompatActivity(), SearchView.OnQueryTextListener
  • después de que se muestre otro error, simplemente mueva el cursor sobre el error y presione alt+Enter
  • entonces tendrá dos funciones llamadas onQueryTextChange() , onQueryTextChange()
  • entonces simplemente implemente estas dos funciones como

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)
           }
       })

¡sí! Hemos implementado con éxito una función de búsqueda. Puede descargar el código fuente final haciendo clic aquí .

Ahora ejecute su aplicación y vea. ¿Su aplicación muestra datos ficticios en la vista del reciclador? si es así, entonces lo ha hecho ahora puede buscar algo y le mostrará los resultados, 

Pero si no, agregue algunos datos ficticios siguiendo algunos pasos como…

  • cree una función como «fun additem()» dentro de su clase MainActivity.kt
  • luego inserte datos usando mainViewModel.insertData(Person(“string : name”, “string: lastname”, int :age)) como se muestra a continuación en el código
  • ahora simplemente llame a la función additem() cuando se haga clic en el botón de acción flotante o como quiera.

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))
}
  • si desea insertar datos usando el botón de acción flotante
  • luego simplemente agregue esta línea a su código de botón de acción flotante

android:onClick=”elemento adicional”

Eso es todo, sus datos también se mostrarán en su aplicación y ahora también puede verificar la búsqueda ……. finalmente, la aplicación está funcionando como

Producción:

Publicación traducida automáticamente

Artículo escrito por eralokyadav2019 y traducido por Barcelona Geeks. The original can be accessed here. Licence: CCBY-SA

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *