Android и Kotlin сопрограммы: неподходящий вызов метода блокировки - PullRequest
6 голосов
/ 10 января 2020

У меня есть следующий класс:

class Repository(
    private val assetManager: AssetManager,
    private val ioDispatcher: CoroutineDispatcher = Dispatchers.IO
) {
    suspend fun fetchHeritagesList(): HeritageResponse = withContext(ioDispatcher) {
        try {
            // TODO Blocking method call?
            val bufferReader = assetManager.open("heritages.json").bufferedReader()
...

, и мне интересно, почему я получаю предупреждение в open("heritages.json"), говорящем Innapropriate blocking method call? не withContext(ioDispatcher) это исправляет?

Спасибо за объяснение!

Ответы [ 2 ]

11 голосов
/ 11 января 2020

Проверка IntelliJ, которая ищет блокировку вызовов внутри приостанавливаемых функций, недостаточно мощна, чтобы увидеть уровень косвенности между Dispatchers.IO и его использованием в withContext. Вот минимальный источник проблемы:

class IoTest {
    private val ioDispatcher: CoroutineDispatcher = Dispatchers.IO

    suspend fun indirectRef() = withContext(ioDispatcher) {
        Thread.sleep(1) // Flagged as inappropriate blocking call
    }

    suspend fun directRef() = withContext(Dispatchers.IO) {
        Thread.sleep(1) // Not flagged
    }
}

Однако, в отличие от моего случая, ваш ioDispatcher открыт для инъекции через конструктор, так что вы можете просто поставить Dispatchers.Main вместо него и что будет представлять собой неуместную блокировку.

К сожалению, я еще не слышал о каком-либо способе формального определения контракта диспетчера как "допускающего блокировку вызовов", чтобы вы могли принудительно применить его в конструктор.

Уже есть похожая проблема, открытая на YouTrack .

0 голосов
/ 10 января 2020

Код ниже может зависнуть из-за блокировки ввода-вывода:

class MyService(assetManager: AssetManager) {
   private val repo = Repository(assetManager, newFixedThreadPoolContext(nThreads: 1, name: "SO QA"))

   suspend fun read(): HeritageResponse {
      return fetchHeritagesList(); // <-- please note, that we replaced IO dispatcher to single-threaded one
   }
}


...