![](/img/trans.png)
[英]Why are the contents of some GlobalScope.launch calls in Kotlin silently failing to execute?
[英]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.