'Filter Listview using Searchview with Custom Adapter in Kotlin

I'm new to android and would like to get some help. I have created a list view in my android and have implemented a search filter method using searchview to search for the name of the image from the database SQLite. However, my list of data does not show up when my search filter method is implemented and not sure what went wrong.

I have searched on many sites to compare the examples but most of the them are either in java or does not fit my program. Your help is greatly appreciated. Here are the codes:

TouristSpotPage:

class TouristSpotPage : AppCompatActivity() {
var myTouristSpotList: ListView? = null
var touristSpotList = ArrayList<DataList>()
var customAdapter: CustomAdapter? = null
var touristSpotImageView: ImageView? = null
var mDatabaseHelper: DatabaseHelper? = null
var name: String? = null
lateinit var image: ByteArray

var id = 0
override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.tourist_spot_page)
    myTouristSpotList = findViewById(R.id.touristSpotListView)
    touristSpotList = ArrayList()
    customAdapter =
        CustomAdapter(this, R.layout.tourist_spot_custom_list_layout, touristSpotList)
    myTouristSpotList!!.adapter = customAdapter
    mDatabaseHelper = DatabaseHelper(this)
    addSomeData() //<<<<<<<<<< FOR ADDING DATA MANUALLY
    val data = mDatabaseHelper!!.getData("SELECT * FROM tourist_spot_table")
    touristSpotList.clear()
    while (data.moveToNext()) {
        id = data.getInt(0)
        name = data.getString(1)
        image = data.getBlob(2)
        touristSpotList.add(DataList(id, name!!, image))
        Log.i("image", String(image))
    }

    search() // Search function
    data.close() //CLOSE CURSOR WHEN DONE WITH IT
    customAdapter!!.notifyDataSetChanged()
    returnHomepage()


}

private fun addSomeData() {
    mDatabaseHelper!!.writableDatabase.delete(
        DatabaseHelper.TABLE_TOURIST_SPOT,
        null,
        null
    ) //<<<<<<<<<< Delete all pets
    mDatabaseHelper!!.addTouristSpotImageFromAssets(
        "Petronas Twin Tower",
        "malaysia-top-attractions-petronas-twin-towers.jpg"
    )
    mDatabaseHelper!!.addTouristSpotImageFromAssets(
        "Batu Caves",
        "malaysia-top-attractions-batu-caves-selangor.jpg"
    )
    mDatabaseHelper!!.addTouristSpotImageFromAssets(
        "Cameron Highland",
        "malaysia-top-attractions-cameron-highlands.jpg"
    )
}

private fun returnHomepage() {
    val returntoHomepage = findViewById<ImageView>(R.id.return_button_icon)
    returntoHomepage.setOnClickListener {
        val intent = Intent(this, Homepage::class.java)
        startActivity(intent)
    }
}

// Search function for searching name from the database
    private fun search()
{
    val lv = findViewById<ListView>(R.id.touristSpotListView)
    val searchBar = findViewById<SearchView>(R.id.SearchBar)

    searchBar.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
        override fun onQueryTextChange(newText: String?): Boolean {

            if(TextUtils.isEmpty(newText)){
                Log.i(TAG,"Search Name")
               (lv.adapter as CustomAdapter?)?.filterName("")
                lv.clearTextFilter()
            }else {
                if (newText != null) {
                    Log.i("Searched", newText)
                    (lv.adapter as CustomAdapter?)?.filterName(newText)
                }

            }
            return true
        }

        override fun onQueryTextSubmit(query: String?): Boolean {
            return false
        }
    })
  }
}

CustomAdapter:

class CustomAdapter(private val context: Context,private val layout: Int,
                private val recordList: ArrayList<DataList>) :
BaseAdapter()
{
    override fun getCount(): Int {
        return recordList.size
    }

    override fun getItem(position: Int): Any {
        return recordList[position]
    }

    override fun getItemId(position: Int): Long {
        return position.toLong()
    }

    private inner class ViewHolder {
        var touristSpotImageView: ImageView? = null
        var touristSpotTextView: TextView? = null
    }

    override fun getView(position: Int, convertView: View?, parent: ViewGroup): View? {
        var v = convertView
        var holder = ViewHolder()
        if (v == null) {
            val layoutInflater =
                context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
            v = layoutInflater.inflate(layout, null)
            holder.touristSpotImageView = v.findViewById(R.id.touristSpotImageView)
            holder.touristSpotTextView = v.findViewById(R.id.touristSpotTextView)
            v.tag = holder
        } else {
            holder = v.tag as ViewHolder
        }
        val datalist = recordList[position]
        holder.touristSpotTextView!!.text = datalist.name
        val recordImage = datalist.image
        val bitmap = BitmapFactory.decodeByteArray(recordImage, 0, recordImage.size)
        holder.touristSpotImageView!!.setImageBitmap(bitmap)
        return v
    }


    var filteredList = ArrayList<DataList>()
    
    fun filterName(Text: String) { // Filter Class
        Log.i("searched inside:", Text)
        var Text = Text

        Text = Text.lowercase(Locale.getDefault())
        if (Text.isEmpty()) {
            filteredList = recordList
        } else {
            for (touristName in recordList) {
                if (touristName.name.lowercase(Locale.getDefault())?.contains(Text)!!) {
                    filteredList = listOf(touristName) as ArrayList<DataList>
                }
            }
        }
        notifyDataSetChanged()
    }
}

DatabaseHelper

class DatabaseHelper(context: Context) :
SQLiteOpenHelper(context, DBNAME, null, DBVERSION) {
var mDB: SQLiteDatabase = this.writableDatabase
var mContext: Context = context
override fun onCreate(db: SQLiteDatabase) {
    val tourist_spot_table = "CREATE TABLE IF NOT EXISTS " + TABLE_TOURIST_SPOT + "(" +
            COLUMN_TOURIST_SPOT_ID + " INTEGER PRIMARY KEY, " +
            COLUMN_TOURIST_SPOT_NAME + " TEXT," +
            COLUMN_TOURIST_SPOT_IMAGE + " BLOB DEFAULT x'00'," +
            COLUMN_TOURIST_SPOT_IMAGEPATH + " TEXT DEFAULT ''" +
            ")"
    db.execSQL(tourist_spot_table)
}



companion object {
    const val DBNAME = "tourists.db"
    const val DBVERSION = 1
    const val TABLE_TOURIST_SPOT = "tourist_spot_table"
    const val COLUMN_TOURIST_SPOT_ID = BaseColumns._ID
    const val COLUMN_TOURIST_SPOT_NAME = "name"
    const val COLUMN_TOURIST_SPOT_IMAGE = "image"
    const val COLUMN_TOURIST_SPOT_IMAGEPATH = "imagepath"
}

override fun onUpgrade(db: SQLiteDatabase, i: Int, i1: Int) {}

/**
 * NOT USED
 * @param touristSpotName
 * @return
 */
fun addTouristSpot(touristSpotName: String?, touristSpotImage: Blob?): Long {
    val cv = ContentValues()
    cv.put(COLUMN_TOURIST_SPOT_NAME, touristSpotName)
    //cv.put(COLUMN_PET_IMAGE,touristSpotImage)
    return mDB.insert(TABLE_TOURIST_SPOT, null, cv)
}

fun addTouristSpotImageFromAssets(touristSpotName: String?, touristSpotImage: String): Long {
    var touristspotimage = ByteArray(0)
    var image_size = 0
    try {
        val `is`: InputStream = mContext.getAssets().open(touristSpotImage)
        image_size = `is`.available()
        touristspotimage = ByteArray(image_size)
        `is`.read(touristspotimage)
        `is`.close()
    } catch (e: IOException) {
    }
    val cv = ContentValues()
    cv.put(COLUMN_TOURIST_SPOT_NAME, touristSpotName)
    if (image_size > 0) {
        cv.put(COLUMN_TOURIST_SPOT_IMAGE, touristspotimage)
    }
    return mDB.insert(TABLE_TOURIST_SPOT, null, cv)
}

fun getData(query: String?): Cursor {
    return mDB.rawQuery(query, null)
}  

}

tourist_spot_page.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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"
android:orientation="vertical">

<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="130dp"
    android:background="@color/light_blue"
    android:orientation="vertical">

    <ImageView
        android:id="@+id/return_button_icon"
        android:layout_width="30dp"
        android:layout_height="30dp"
        android:src="@drawable/return_icon"
        android:layout_margin="15dp"
        >
    </ImageView>

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="10dp"
        android:text="@string/title"
        android:textSize="24sp"
        android:textStyle="bold"
        android:textColor="@color/black"
        android:textAlignment="center"
        />
</LinearLayout>

<androidx.appcompat.widget.Toolbar
    android:id="@+id/toolbar"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="@drawable/search_box_shape"
    android:elevation="10dp"
    android:layout_marginTop="10dp"
    android:layout_marginBottom="10dp">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:gravity="center|right"
        android:layout_marginRight="20dp"
        android:orientation="vertical">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:gravity="center|right">

            <SearchView
                style="@style/MaterialSearchBarLight"
                android:id="@+id/SearchBar"
                android:layout_width="match_parent"
                android:layout_height="48dp"
                android:layout_margin="5dp" />

        </LinearLayout>
    </LinearLayout>

</androidx.appcompat.widget.Toolbar>
   <ListView
    android:id="@+id/touristSpotListView"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">
   </ListView>

  <TextView
    android:id="@+id/emptyTextView"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_centerInParent="true"
    android:text="@string/noresult"
    android:textSize="20sp"
    android:visibility="gone">
  </TextView>
</LinearLayout>


Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source