Issue
After a break I am trying to finish my first android app and in the process of converting it to Kotlin. All has gone well but I am getting the warning on Async tasks that are making calls to a locally stored SQL database and the error is that the Async call should be static or it will leak.
So I intend on doing it right and from what I have read so far I need to use Globalscope.launch.
Here is the code I used to use to access the database on another thread.
private class MyAsyncTask extends AsyncTask<String, String, String>
{
@Override protected String doInBackground (String... params)
{
//SQL tasks, open read and close database
}
@Override protected void onPostExecute(String result)
{
// Tasks on retrieved database.
}
@Override protected void onPreExecute()
{ }
@Override protected void onProgressUpdate(String... text) {}
}
I did a Kotlin conversion and it produced this code of which I am receiving the should be static or will cause a memory leak warning:
private inner class MyAsyncTask : AsyncTask<String, String, String>() {
override fun doInBackground(vararg params: String): String?
{
//SQL tasks, open read and close database
}
override fun onPostExecute(result: String)
{
// Tasks on retrieved database.
}
override fun onPreExecute() {}
override fun onProgressUpdate(vararg text: String)
{}
}
This is how I believe I should now perform a SQL call on a seperate thread in Kotlin
private inner class MyAsyncTask()
{
GlobalScope.launch {
//SQL tasks, open read and close database
}
Thread.sleep(2000L) // block main thread for 2 seconds to keep JVM alive
// Tasks on retrieved database.
}
Is the GlobalScope.launch the best and safest way to make a call to a locally stored SQL database and if not, what is the correct method?
Solution
After a week reading lots and trying to get the right solution for my needs I found the solution by Ian Alexander the most helpful. @Rene's solution is good but not exactly what I needed but it did give me clues so thanks @Rene.
Caveat, this is for Kotlin 1.3 so Android Studio might recommend you upgrade to the later versions.
Step 1. Ensure your build.gradle has both the following as both are needed for Dispatch.Main
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.0.0'
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.0.0'
Step 2.
import kotlinx.coroutines.*
class MainActivity : AppCompatActivity() {
protected val mySQLScope = CoroutineScope(Dispatchers.Main)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
//MAIN UI setup
println("Setting up Activity Main")
//get SQL database loaded in background
getSQLDatabase()
}
fun getSQLDatabase() {
mySQLScope.launch {
val user = withContext(Dispatchers.IO){
getSQLTASK()
}
//Any code here is blocked till getSQLTASK is finished
println("getSQLTASK now finished")
//Retrieved Database Now Usable
}
}
suspend fun getSQLTASK(){
//Code here blocks the main coroutine but does not affect the main thread.
delay(2000)
println("In getSQLTASK")
//SQL DATABASE LOADED HERE
}
}
So this works but if I want to ensure the process stops if the user swaps to another app then I will need to do the following:
import kotlinx.coroutines.*
class MainActivity : AppCompatActivity() {
protected val coroutineSup = SupervisorJob()
protected val mySQLScope = CoroutineScope(Dispatchers.Main + coroutineSup)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
//MAIN UI setup
println("Setting up Activity Main")
//get SQL database loaded in background
getSQLDatabase()
}
fun getSQLDatabase() {
mySQLScope.launch {
val user = withContext(Dispatchers.IO){
getSQLTASK()
}
//Any code here is blocked till getSQLTASK is finished
println("getSQLTASK now finished")
//Retrieved Database Now Usable
}
}
suspend fun getSQLTASK(){
//Code here blocks the main coroutine but does not affect the main thread.
delay(2000)
println("In getSQLTASK")
//SQL DATABASE LOADED HERE
}
@CallSuper
override fun onPause() {
super.onPause()
coroutineSup.cancel()
//now crash avoided if user leaves app.
}
}
This adds a supervisor that cancels the SQL retrieval if the app is no longer actively used.
Hope this helps someone as it took a week of reading to get my head around it.
Answered By - timv
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.