'want to create new thread in android studio kotlin for setOnItemClickListener on listview to open new activity by taking data from database

want to create new thread in android studio kotlin for setOnItemClickListener on listview to open a new activity by taking data from database . i am doing this on main thread which making my app freeze and also some times it is taking more than 2, 3 clicks on list item to open respective activity of item that i clicked.

package com.example.countriescapitals_continentwise

import android.content.Intent
import android.os.AsyncTask
import android.os.Bundle
import android.text.PrecomputedText
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ListView
import android.widget.ProgressBar
import android.widget.SearchView
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import javax.xml.transform.Result

// TODO: Rename parameter arguments, choose names that match
// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
private const val ARG_PARAM1 = "param1"
private const val ARG_PARAM2 = "param2"

/**
 * A simple [Fragment] subclass.
 * Use the [AsiaFrag.newInstance] factory method to
 * create an instance of this fragment.
 */
class AsiaFrag : Fragment() {
    // TODO: Rename and change types of parameters
    private var param1: String? = null
    private var param2: String? = null
    private var  asyncTask:AsyncTask<PrecomputedText.Params,ProgressBar,Result>?=null
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        arguments?.let {
            param1 = it.getString(ARG_PARAM1)
            param2 = it.getString(ARG_PARAM2)
        }
    }

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        // Inflate the layout for this fragment
        val asiaLayout= inflater.inflate(R.layout.fragment_asia, container, false)

        val mAsiaLv:ListView=asiaLayout.findViewById(R.id.asialv_id)

        val msearchvw:androidx.appcompat.widget.SearchView=asiaLayout.findViewById(R.id.asiasearchid)
        msearchvw.queryHint="Search Among Countries"
        msearchvw.isIconified=false





        val dbHelper=AssetOpenHelper(requireActivity())
        val dataBase=dbHelper.readableDatabase
        var myCursor=dataBase.rawQuery("SELECT * FROM ASIA",null)

        val mCursorAdapter=CustomCursorAdapter(requireContext(),myCursor)
        mAsiaLv.adapter=mCursorAdapter



        //on item click listner go to other activity
     mAsiaLv.setOnItemClickListener { parent, view, position, id->


         var mcountryName=myCursor?.getString(1)
         var mcapitalName=myCursor?.getString(2)
         var mcurrencyName=myCursor?.getString(3)
         var mlanguageName=myCursor?.getString(4)
         var mareaName=myCursor?.getString(6)
         var mpopulation=myCursor?.getString(5)
         var mimageName=myCursor?.getString(7)

         val intentToDetails= Intent(requireContext(),CountryDetails::class.java)
            intentToDetails.putExtra("icountryName",mcountryName)
            intentToDetails.putExtra("icapitalName",mcapitalName)
            intentToDetails.putExtra("icurrencyName",mcurrencyName)
            intentToDetails.putExtra("ilanguageName",mlanguageName)
            intentToDetails.putExtra("iareaName",mareaName)
            intentToDetails.putExtra("ipopulation",mpopulation)
            intentToDetails.putExtra("iimageName",mimageName)

            startActivity(intentToDetails)

        }

        // code for search view to search among listview items
        msearchvw.setOnQueryTextListener(object : SearchView.OnQueryTextListener,
            androidx.appcompat.widget.SearchView.OnQueryTextListener {
            override fun onQueryTextSubmit(p0: String?): Boolean {
                return false
            }

            override fun onQueryTextChange(p0: String?): Boolean {

                myCursor=dataBase.rawQuery("SELECT * FROM ASIA WHERE COUNTRY LIKE '%${p0}%' OR CAPITAL LIKE '${p0}'",null )
                mCursorAdapter.changeCursor(myCursor)
                return false
            }

        }
        )



        return asiaLayout
    }

    companion object {
        /**
         * Use this factory method to create a new instance of
         * this fragment using the provided parameters.
         *
         * @param param1 Parameter 1.
         * @param param2 Parameter 2.
         * @return A new instance of fragment AsiaFrag.
         */
        // TODO: Rename and change types and number of parameters
        @JvmStatic
        fun newInstance(param1: String, param2: String) =
            AsiaFrag().apply {
                arguments = Bundle().apply {
                    putString(ARG_PARAM1, param1)
                    putString(ARG_PARAM2, param2)
                }
            }
    }




}

///////////////// this is my xml file

<

?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    tools:context=".AsiaFrag">
<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
 android:orientation="vertical">

<androidx.appcompat.widget.SearchView
    android:id="@+id/asiasearchid"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"/>

 <ListView
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:id="@+id/asialv_id"/>
</LinearLayout>
</FrameLayout>

/////////////// sqlite data base open helper

package com.example.countriescapitals_continentwise

import android.app.Activity
import android.content.Context
import android.database.sqlite.SQLiteDatabase
import android.database.sqlite.SQLiteOpenHelper
import android.util.Log
import androidx.fragment.app.FragmentActivity
import java.io.File
import java.io.FileOutputStream

/// creating constants
const val dbName = "COUNTRY_DETAILS.db"
const val dbVersionNumber = 1

class AssetOpenHelper(private val context: Context):SQLiteOpenHelper(context,dbName,null, dbVersionNumber) {

    private var dataBase:SQLiteDatabase?=null

    init {
        // Check if the database already copied to the device.
        val dbExist = checkDatabase()
        if (dbExist) {
            // if already copied then don't do anything.
            Log.e("-----", "Database exist")
        } else {
            // else copy the database to the device.
            Log.e("-----", "Database doesn't exist")
            createDatabase()
        }
    }

    private fun createDatabase() {
        copyDatabase()
    }

    private fun checkDatabase(): Boolean {
        val dbFile = File(context.getDatabasePath(dbName).path)
        return dbFile.exists()
    }


    private fun copyDatabase() {

        val inputStream = context.assets.open("databases/$dbName")
        val outputFile = File(context.getDatabasePath(dbName).path)
        val outputStream = FileOutputStream(outputFile)

        val bytesCopied = inputStream.copyTo(outputStream)
        Log.e("bytesCopied", "$bytesCopied")

        inputStream.close()
        outputStream.flush()
        outputStream.close()
    }

    // Open the database with read and write access mode.
    private fun openDatabase() {
        dataBase = SQLiteDatabase.openDatabase(context.getDatabasePath(dbName).path, null, SQLiteDatabase.OPEN_READWRITE)
    }

    // Close the database.
    override fun close() {
        dataBase?.close()
        super.close()
    }



    override fun onCreate(p0: SQLiteDatabase?) {

    }

    override fun onUpgrade(p0: SQLiteDatabase?, p1: Int, p2: Int) {

    }

}


Solution 1:[1]

Never do Database operation in main thread.

always create a separate function for database operations. Use loader to prevent user from clicking multiple times.

    viewModelScope.launch(){
                dbOperations()
            }

    private suspend fun dbOperations() {
       //Do your db task here. its background thread
            withContext(Dispatchers. Main) {

              //call next activity here. it is main thread.
    
            }
        }

Sources

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

Source: Stack Overflow

Solution Source
Solution 1 vignesh