2016-10-28 3 views
2

У меня есть метод, который загружает изображение из Firebase Storage. Он вызван в фоновом потоке, и мне нужно заблокировать его, пока изображение не будет загружено (чтобы избежать обратного ад). Вот код (в Котлин)CountDownLatch не освобождает нить

override fun fromNet(): Bitmap? { 
    Log.wtf(TAG, "$name loading from firebase") 
    var result: Bitmap? = null 
    val lock = CountDownLatch(1) 
    try { 
     FirebaseStorage.getInstance().getReferenceFromUrl(FIRE_STORAGE).child(ctx.getKGL().famkey) 
      .child(name).getBytes(524288L) 
      .addOnFailureListener { 
       Log.wtf(TAG, "$name load failure") 
       lock.countDown() 
      } 
      .addOnSuccessListener { bytes -> 
       Log.wtf(TAG, "$name loaded") 
       val b = BitmapFactory.decodeByteArray(bytes, 0, bytes.size).scale(ctx.dip(64)) 
       result = b 
       lock.countDown() 
       ctx.saveToCache(name, b) 
      } 
      .addOnCompleteListener { 
       Log.wtf(TAG, "on complete") 
       lock.countDown() 
      } 
    } catch (ignored: NullPointerException) { lock.countDown() } 
    lock.await() 
    return result 
} 

Но поток остается заблокирован навсегда

Logcat:

A/MemberPhoto: xvd6z67gZfMCLG4c9mkGXKe9ML53 load failure 
A/MemberPhoto: on complete 

UPD: Может быть причиной, что Firebase код Java, и мой код в Котлине?

+0

Ну, 'lock.await()' никогда не разблокирует, по крайней мере, если 'NullPointerException' брошен в 'try' перед вызовом' lock.countDown() '. Разве это не так? – hotkey

+0

@hotkey Я думал, что если исключение выбрано - wait() не будет вызвано. Но позвольте мне проверить –

+0

. Мой плохой, я не заметил «return null» в блоке 'catch'. Сожалею. – hotkey

ответ

2

Если вы хотите быть уверены, что lock.await() не сделает ваш текущий поток ждать вечно, вы должны убедиться, что lock.countDown() называется то, что бывает так, здесь вы должны окружать с try/finally блоком кода ваших слушателей, чтобы позвонить lock.countDown() в блоке finally.

Действительно в противном случае с вашим текущим кодом, если, например, BitmapFactory.decodeByteArray(bytes, 0, bytes.size).scale(ctx.dip(64)), lock.countDown() никогда не будет вызван, который вызовет поток, вызывающий lock.await(), навсегда.

Например, в случае успеха код вашего слушателя должно быть достаточно:

.addOnSuccessListener { bytes -> 
    try { 
     Log.wtf(TAG, "$name loaded") 
     val b = BitmapFactory.decodeByteArray(bytes, 0, bytes.size).scale(ctx.dip(64)) 
     result = b 
    } finally { 
     lock.countDown() 
    }   
    ctx.saveToCache(name, b) 
} 
+0

BTW, ошибки не выбрасываются, но это работает –

Смежные вопросы