Как ограничить вызов функции конкретным потоком / исполнителем - PullRequest
0 голосов
/ 30 июня 2018

В настоящее время я разрабатываю базу данных для мобильного приложения. Недавно я нашел очень полезную функцию для доступа к базе данных в фоновом режиме:

private val IO_EXECUTOR = Executors.newSingleThreadExecutor()

fun ioThread(f : () -> Unit) {
    IO_EXECUTOR.execute(f)
}

Кроме того, я выяснил, что код синхронизации не нужен, так как к базе данных будет обращаться только в одном потоке (то есть в потоке, используемом SingleThreadExecutor).

Единственная проблема заключается в том, что следующие методы должны быть ограничены, чтобы вызываться только через функцию ioThread (или с использованием IO_EXECUTOR).

abstract class MyDatabase : RoomDatabase() {
    companion object {
        fun init(context: Context) { ... }
        fun getInstance() { ... }
    }

Можно ли добиться этого за Kotlin / Java?


ОБНОВЛЕНИЕ: на данный момент у меня есть эта реализация, но думаю, что должны быть лучше

// App.kt file
private val IO_EXECUTOR = Executors.newSingleThreadExecutor()
private var IO_THREAD_ID: Long = -1L

private fun getIOThreadId(): Long {
    if (IO_THREAD_ID == -1L)
        IO_THREAD_ID = IO_EXECUTOR.submit(Callable<Long> { Thread.currentThread().id }).get()

    return IO_THREAD_ID
}

fun notInIOThread() = Thread.currentThread().id != getIOThreadId()

fun ioThread(f : () -> Unit) {
    IO_EXECUTOR.execute(f)
}

и затем использовать notInIOThread() в init() и getInstance() функциях

Ответы [ 3 ]

0 голосов
/ 30 июня 2018

Я предполагаю, что вы хотите, чтобы функции вызывались только внутри ioThread блока кода, иначе возникла бы ошибка типа. Сначала сделайте их членами-функциями класса с помощью конструктора, недоступного пользовательскому коду, чтобы другие не могли вызвать его напрямую:

class MyDslClass internal constructor() {
    fun init(context: Context) { ... }
    fun getInstance() { ... }
}

А ioThread должно быть:

fun ioThread(f : MyDslClass.() -> Unit) {
    val dsl = MyDslClass()
    IO_EXECUTOR.execute { dsl.f() }
}

Тогда вы можете ограничить вызовы этих функций только внутри блока ioThread.

fun main(args: Array<String>) {
    ioThread {
        getInstance() // Ok
    }
    // cannot call `getInstance` since I cannot construct a `MyDslClass`
}
0 голосов
/ 30 июня 2018

Если вам абсолютно необходимо убедиться, что код выполняется в правильном потоке, вы можете использовать пользовательский поток, а затем проверить Thread.currentThread() для интерфейса.

private interface MarkedIOThread // Marker interface

private val IO_EXECUTOR = Executors.newSingleThreadExecutor { r -> 
    return object : Thread(r), MarkedIOThread 
}

fun notInIOThread(): Boolean = Thread.currentThread() !is MarkedIOThread
0 голосов
/ 30 июня 2018

Да, вы можете использовать аннотацию Android-аннотации Worker Thread.

Когда вы аннотируете метод или класс с помощью @WorkerThread, android выдаст вам ошибки, если вы вызовете его из потока пользовательского интерфейса.

Подробнее о @WorkerThread можно прочитать здесь: https://developer.android.com/reference/android/support/annotation/WorkerThread

И еще об аннотациях для Android здесь: https://developer.android.com/studio/write/annotations

Я бы посоветовал вам проверить библиотеку комнаты: https://developer.android.com/topic/libraries/architecture/room

Это очень мощно, если у вас нет особых причин для создания библиотеки базы данных, вам лучше всего подойдет комната.

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