簡體   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