#java #kotlin #kotlin-coroutines
#java #kotlin #kotlin-сопрограммы
Вопрос:
Я решил написать этот вопрос, поскольку пока нет лучших практик по этой теме.
Мы предоставляем Android SDK, который реализует асинхронные вызовы с сопрограммами. Я хочу, чтобы наши клиенты использовали приостанавливающие функции и Flow
из Java или стандартного Kotlin.
Я знаю, что есть kotlinx-coroutines-jdk8, но это можно использовать только с 24-го уровня Api Android, а наш SDK поддерживает Android вплоть до 21-го уровня Api. Так что на данный момент это не вариант.
Моя идея состояла в том, чтобы соединить миры Java (или стандартного Kotlin) и сопрограмм, предоставив простой API обратного вызова.
Я хотел бы знать, является ли мой следующий подход хорошим решением. Есть ли какие-то недостатки или опасности? Какая альтернатива у меня была бы, чтобы заставить клиентов вызывать функции сопрограмм, не заставляя их самостоятельно использовать сопрограммы?
А теперь давайте начнем. Сначала я покажу вам некоторые интерфейсы и вспомогательные функции, которые я могу использовать позже для сопоставления функций приостановки и потока.
Отмена бронирования
Мне нужно убедиться, что сопрограмма может быть отменена из Java. Итак, я создал Cancelable
интерфейс.
interface Cancelable {
fun cancel()
}
Этот интерфейс реализуется CancelableJob
тем, что содержит и скрывает Job
подлежащее отмене.
class CancelableJob(private val job: Job) : Cancelable {
override fun cancel() {
job.cancel()
}
}
Запустите новую сопрограмму
Каждый раз, когда клиент вызывает функцию, я запускаю новую сопрограмму. Для этого я создаю функцию верхнего уровня launchCancelableJob
. Эта функция получает приостанавливающий блок и возвращает a Cancelable
. Сопрограмма будет запущена Dispatchers.Main
, поэтому все результаты можно будет наблюдать в потоке пользовательского интерфейса вместе с SupervisedJob
.
fun launchCancelableJob(block: suspend () -> Unit): Cancelable {
val job: Job = CoroutineScope(Dispatchers.Main SupervisorJob()).launch {
block.invoke()
}
return CancelableJob(job)
}
Перенесите функцию приостановки и поток в мир Java
Теперь пришло время предоставить функцию моста, которая сама по себе не является функцией приостановки, но запускает сопрограмму и возвращает a Cancelable
. После заданного обратного вызова результат будет доставлен вызывающему абоненту.
// normal coroutine api
suspend fun generateQrCode(): QrCode
// bridge function - to be called from Java
fun generateQrCode(callback: (QrCode) -> Unit): Cancelable {
return launchCancelableJob {
val qrCode: QrCode = generateQrCode()
callback(qrcode)
}
}
То же самое я мог бы сделать с потоком.
// normal coroutine api
fun generateQrCodes(): Flow<QrCode>
// bridge function - to be called from Java
fun generateQrCodes(callback: (QrCode) -> Unit): Cancelable {
return launchCancelableJob {
generateQrCodes().collect { qrCode: QrCode ->
callback(qrcode)
}
}
}
Использование
Вышеупомянутая функция может быть вызвана из Java следующим образом:
Cancelable cancelable = generateQrCode(new Function1<QrCode, Unit>() {
@Override
public Unit invoke(QrCode qrCode) {
// show the qrCode
return Unit.INSTANCE;
}
});
И если он больше не нужен, его можно отменить, например:
cancelable.cancel();
Это мой подход. Я действительно с нетерпением жду ваших мнений или, возможно, лучших решений. Спасибо за чтение, я знаю, что это был очень длинный вопрос.
Комментарии:
1. Возможно, стоит задать этот вопрос на CodeReview , если вы ищете отзывы о качестве вашего кода.
2. @AlexRudenko Я согласен, что этот пост слишком широк / субъективен для SO и может подойти для CR. Было бы здорово, если бы было также предложение типа » Пожалуйста, прочитайте соответствующие страницы справочного центра, например: » О каких темах я могу спросить здесь? ‘ и ‘ Как мне задать хороший вопрос? «. Стандарт сайта на CR заключается в том, что заголовок описывает, что делает код, а не цели проверки, поэтому их следует изменить, и напоминает о том, что весь код должен быть размещен для полной перспективы проверки.