Kotlin SQL звонки с использованием GlobalScope - PullRequest
0 голосов
/ 09 ноября 2018

После перерыва я пытаюсь завершить свое первое приложение для 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) 
{}
}

Вот как я считаю, что теперь я должен выполнить вызов SQL для отдельного потока в 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.
}

Является ли GlobalScope.launch лучшим и самым безопасным способом вызова локальной базы данных SQL, и если нет, то какой метод правильный?

Ответы [ 3 ]

0 голосов
/ 09 ноября 2018

Сочетание AsyncTask и сопрограмм не имеет смысла. Оба способа выполнить что-то в фоновом потоке. Особенно Thread.sleep() против основной идеи сопрограмм: «неблокирующие потоки».

Хорошее объяснение сопрограмм и пользовательского интерфейса: https://github.com/Kotlin/kotlinx.coroutines/blob/master/ui/coroutines-guide-ui.md#structured-concurrency-lifecycle-and-coroutine-parent-child-hierarchy

Я просто адаптировал основную часть примера, чтобы вы поняли, как его использовать:

//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
    }                
}
0 голосов
/ 16 ноября 2018

После недели чтения лотов и попыток найти правильное решение для своих нужд я нашел решение Ian Alexander наиболее полезным. @ Решение Рене хорошее, но не совсем то, что мне было нужно, но оно дало мне подсказку, спасибо, Рене.

Предостережение , это для 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, если приложение больше не используется.

Надеюсь, это кому-то поможет, так как на чтение мне понадобилась неделя чтения.

0 голосов
/ 09 ноября 2018

Использование GlobalScope возможно, но это не лучший способ. Вы должны использовать местный CoroutineScope. Смотрите эту статью Романа Елизарова: https://medium.com/@elizarov/structured-concurrency-722d765aa952

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...