休息后,我正试图完成我的第一个android应用程序,并将其转换为Kotlin。一切都很顺利,但我收到了关于异步任务的警告,这些任务正在调用本地存储的SQL数据库,错误是异步调用应该是静态的,否则就会泄漏。
所以我打算把它做好,从我目前所读到的内容来看,我需要使用Globalscope.slaunch.
这是我用来访问另一个线程上的数据库的代码。
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.slaunch是调用本地存储的SQL数据库的最佳和最安全的方法吗?如果不是,正确的方法是什么?
AsyncTask
和Coroutines的组合毫无意义。两者都是在后台线程上执行某些内容的方法。特别是Thread.sleep()
反对协同程序的主要思想:"非阻塞线程"。
协程和UI的一个很好的解释是:https://github.com/Kotlin/kotlinx.coroutines/blob/master/ui/coroutines-guide-ui.md#structured-并发生命周期与协同程序父子层次
我只是修改了示例的主要部分,让您了解如何使用:
//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/结构-一致性-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检索。
希望这能帮助到别人,因为我花了一周的时间才明白