Я разрабатываю на Android и в моем исходном коде много слушателей на основе обратного вызова. Я хочу преобразовать часть из них в поток kotlin. Я читал много статей, где говорится о callbackFlow, но не думаю, что это правильный выбор.
В моем случае что-то вроде этого:
interface ActionListener{
public void actionStarted(actionId:Int)
public void actionProgress(actionId:Int, elementCreated:ExampleElement)
public void actionEnd(actionId:Int)
}
class MainProductor{
ActionListener actionListener;
MainProductor(ActionListener actionListener){
this.actionListener = actionListener
}
void start(){
//start some heavy works that start to call actionListener
}
}
Вариант использования: когда я вызываю start, начинается какое-то действие с определенным идентификатором и начинается создание некоторого ExampleElement В пользовательском интерфейсе я должен показать список ExampleElement, созданный действиями с идентификатором A и с идентификатором B.
В пользовательском интерфейсе я должен показать прогресс, когда запускается одно из обоих действий и пока не будут созданы все элементы, созданные двумя идентификаторами действия, (эта часть очень сложная)
как можно продолжать использовать этот ActionListener и адаптировать его к новому потоку kotlin? Возможен способ?




interface ActionListener {
fun actionStarted(actionId: Int)
fun actionProgress(actionId: Int, progress: Float, elementCreated: ExampleElement)
fun actionEnd(actionId: Int)
}
class MainProductor(val actionListener: ActionListener) {
fun start() {
//start some heavy works that start to call actionListener
}
}
Суть использования callbackFlow заключается в том, что он автоматически регистрирует и отменяет регистрацию слушателя при запуске/отмене. Возможным решением для работы с несколькими методами обратного вызова было бы создание соответствующих классов событий и их генерация.
sealed interface ActionListenerEvent {
class Started(val actionId: Int) : ActionListenerEvent
class ProgressChanged(val actionId: Int, val progress: Float, val elementCreated: ExampleElement) : ActionListenerEvent
class Finished(val actionId: Int) : ActionListenerEvent
}
fun actionEvents() = callbackFlow {
val listener = object : ActionListener {
override fun actionStarted(actionId: Int) {
trySend(ActionListenerEvent.Started(actionId))
}
override fun actionProgress(actionId: Int, progress: Float, elementCreated: ExampleElement) {
trySend(ActionListenerEvent.ProgressChanged(actionId, progress, elementCreated))
}
override fun actionEnd(actionId: Int) {
trySend(ActionListenerEvent.Finished(actionId))
}
}
registerListener(listener)
awaitClose {
unregisterListener(listener)
}
}
Если вам нужно решение, которое лучше контролирует, когда ваш слушатель зарегистрирован/не зарегистрирован, вы также можете использовать MutableSharedFlow для отображения событий.
class MainProductor{
val events = MutableSharedFlow<ActionListenerEvent>() // may need to configure replay and buffer depending on your specific use case
private val listener = object : ActionListener {
override fun actionStarted(actionId: Int) {
events.tryEmit(ActionListenerEvent.Started(actionId))
}
override fun actionProgress(actionId: Int, progress: Float, elementCreated: ExampleElement) {
events.tryEmit(ActionListenerEvent.ProgressChanged(actionId, progress, elementCreated))
}
override fun actionEnd(actionId: Int) {
events.tryEmit(ActionListenerEvent.Finished(actionId))
}
}
fun start(){
registerListener(this.listener)
}
fun stop(){
unregisterListener(this.listener)
}
}
Хотя я не совсем уверен в ожидаемом поведении, особенно в том, что делать с частью elementCreated: ExampleElement, я предполагаю, что вы хотите отобразить список текущих действий с их соответствующим прогрессом. Объединение событий в такой список может выглядеть примерно так:
data class RunningAction(val id: Int, val progress: Float)// TODO integrate "elementCreated"
fun collectEvents() = flow {
val runningActions = mutableMapOf<Int, RunningAction>()
actionEvents().collect { event ->
when (event) {
is ActionListenerEvent.Started -> {
runningActions[event.actionId] = RunningAction(id = event.actionId, progress = 0f)
}
is ActionListenerEvent.ProgressChanged -> {
val action = runningActions[event.actionId]
if (action != null){
runningActions[event.actionId] = action.copy(progress = event.progress) // TODO integrate "elementCreated"
}
}
is ActionListenerEvent.Finished -> {
runningActions.remove(event.actionId)
}
}
emit(runningActions.values)
}
}
Спасибо. попробую вашу идею! Используя вашу идею, если из модели представления я хочу собирать события и показывать все элементы двух разных идентификаторов действий, как я могу это сделать? Какой оператор я могу использовать на нем?
@aeroxr1 Aeroxr1 Я добавил возможную реализацию для объединения событий, не уверен, что она полностью соответствует ожидаемому поведению, но вы сможете использовать ее в качестве основы.
Я добавил вариант использования в вопрос :)
Что ты пытаешься мне сказать? :D Хорошо, вы преобразовали код в kotlin, но это не моя «проблема».