繁体   English   中英

使用GlobalScope的Kotlin SQL调用

[英]Kotlin SQL calls using GlobalScope

休息一会后,我试图完成我的第一个android应用程序,并将其转换为Kotlin。 一切进展顺利,但我收到有关正在调用本地存储的SQL数据库的异步任务的警告,并且错误是异步调用应该是静态的,否则它将泄漏。

所以我打算正确地做它,到目前为止,我需要使用Globalscope.launch。

这是我用来在另一个线程上访问数据库的代码。

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

}

我进行了Kotlin转换,并且产生了我收到的以下代码,该代码应该是静态的,否则会引起内存泄漏警告:

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

这就是我认为现在应该在Kotlin中的单独线程上执行SQL调用的方式

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

GlobalScope.launch是调用本地存储的SQL数据库的最佳和最安全的方法吗?如果不是,正确的方法是什么?

AsyncTask和协程的组合没有任何意义。 两者都是在后台线程上执行某些操作的方法。 特别是Thread.sleep()违反了协程的主要思想:“非阻塞线程”。

协程和UI的很好解释是这样的: https : //github.com/Kotlin/kotlinx.coroutines/blob/master/ui/coroutines-guide-ui.md#structured-concurrency-lifecycle-and-coroutine-parent-子等级

我只是修改了示例的主要部分,以使您了解如何使用:

//Create an own coroutine scope for your activity
class MainActivity : AppCompatActivity(), CoroutineScope {
    protected lateinit var job: Job
    override val coroutineContext: CoroutineContext 
        get() = job + Dispatchers.Main

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        job = Job()
    }

    //destroy all coroutines, when the activity is going down    
    override fun onDestroy() {
        super.onDestroy()
        job.cancel()
    } 

    //start a new coroutine 
    fun loadDataFromSQL() = launch { // Is invoked in UI context with Activity's job as a parent
        val data = withContext(Dispatchers.IO) { // runs in background
            //sql access
        }
        //runs in UI thread
        // display data
    }                
}

可以使用GlobalScope,但这不是最佳方法。 您应该使用本地CoroutineScope。 请参阅Roman Elizarov撰写的这篇文章: https ://medium.com/@elizarov/structured-concurrency-722d765aa952

经过一周的阅读并尝试找到适合我需要的正确解决方案后,我发现Ian Alexander的解决方案最有帮助。 @Rene的解决方案很好,但不是我真正需要的解决方案,但是确实提供了我一些线索,非常感谢@Rene。

警告 ,这是针对Kotlin 1.3的,因此Android Studio可能建议您升级到更高版本。

步骤1.确保您的build.gradle具有以下两项,因为Dispatch.Main都需要

implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.0.0'
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.0.0'

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

因此这可行,但是如果我要确保在用户交换到另一个应用程序后该过程停止,那么我将需要执行以下操作:

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

如果不再活跃使用该应用程序,则会添加一个主管来取消SQL检索。

希望这对某人有所帮助,因为花了一个星期的时间让我理解。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM