Сборка мусора приостановлена ​​сопрограмма задача - PullRequest
0 голосов
/ 19 марта 2020

Я использую kotlin сопрограммы для отображения диалогов подтверждения и обработки результата.

suspend fun showConfirmationDialog() = suspendCancellableCoroutine<Boolean> { cont ->
    val dialog = AlertDialog.Builder(this)
            .setMessage("Are you sure?")
            .setPositiveButton("Yes", { _, _ -> cont.resume(true) })
            .setNegativeButton("No", { _, _ -> cont.resume(false) })
            .setCancelable(true)
            .setOnCancelListener { cont.cancel() }
            .create()

    dialog.show()
    cont.invokeOnCompletion { dialog.dismiss() }
}

Но я чувствую, что этот код подвержен утечке памяти, в случае, если продолжение не возобновлено, задача будет запущена навсегда. Как правильно отменить задание?

1 Ответ

1 голос
/ 19 марта 2020

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

НО, когда вы звоните suspendCoroutine, вы ДОЛЖНЫ убедиться, что Continuation, который вы получите, вернется возобновиться. Это не только из-за утечек памяти. В блоках finally могут происходить самые разные важные вещи, которые будут выполняться только при возобновлении Continuation - снятие блокировок, закрытие файлов и соединений и т. Д. c. et c.

Если во время построения диалога выдается исключение или show, ваша сопрограмма просто не будет приостановлена, так что об этом уже позаботились.

Но убедитесь, что есть этот диалог не может быть закрыт без возобновления продолжения. Вы, вероятно, хотите использовать onDismissListener.

Кроме того, мне не известен метод или расширение invokeOnCompletion для CancellableContinuation ... Убедитесь, что он делает то, что вы хотите, или просто не используйте его.

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

suspend fun showConfirmationDialog() : Boolean {
    var dialog : Dialog?
    try {
        return suspendCancellableCoroutine<Boolean> { cont ->
            val newDialog = AlertDialog.Builder(context)
                .setMessage("Are you sure?")
                .setPositiveButton("Yes", { _, _ -> cont.resume(true) })
                .setNegativeButton("No", { _, _ -> cont.resume(false) })
                .setCancelable(true)
                .setOnDismissListener { dialog = null;cont.cancel() }
                .create()

            newDialog.show()
            dialog = newDialog
        }
    } finally {
        dialog?.dismiss()
    }
}
...