Issue
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
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.
}
}
Answered By - vignesh
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.