Kotlin Потоки Java Обратный вызов взаимодействия - PullRequest
0 голосов
/ 09 марта 2020

Я искал подходящее решение или лучшую практику, когда хочу использовать Kotlin Потоки с обычными обратными вызовами. Мой пример использования - я пишу библиотеку kotlin, которая использует Kotlin Flow для внутреннего использования, и я должен предположить, что пользователи будут использовать Java, например. Поэтому я подумал, что лучшим решением является перегрузка базового интерфейса обратного вызова c для моего метода потока и вызов его в collect примерно так:

class KotlinClass {

    interface Callback {
        fun onResult(result: Int)
    }

    private fun foo() = flow {
        for (i in 1..3) {
            emit(i)
        }
    }

    fun bar(callback: Callback) {
        runBlocking {
            foo().collect { callback.onResult(it) }
        }
    }

  private fun main() {
    bar(object : Callback {
        override fun onResult(result: Int) {
            TODO("Not yet implemented")
        }
    })
}

и в моем приложении Java, которое я могу просто используйте это так:

public class JavaClass {

    public void main() {
        KotlinClass libraryClass = new KotlinClass();
        libraryClass.bar(new KotlinClass.Callback() {
            @Override
            public void onResult(int result) {
                // TODO("Not yet implemented")
            }
        });
    } 
}

Я не уверен, что путь к go, потому что я хотел бы иметь мою библиотеку Kotlin, которая использует потоки, пригодные для использования в хорошем качестве для Java и Kotlin.

Я сталкивался с callbackFlow, но, похоже, это произойдет только в том случае, если я захочу, чтобы он назывался потоковым, если это API на основе обратного вызова? Потому что я новичок в Kotlin и Flows, пожалуйста, извинитесь, если мой вопрос неверен из-за отсутствия некоторых базовых c концепций kotlin.

Ответы [ 2 ]

3 голосов
/ 09 марта 2020

Я бы дал клиенту Java больше контроля над потоком. Я бы добавил onStart и onCompletion метод к вашему интерфейсу обратного вызова. Помимо этого я бы использовал собственный CoroutineScope - возможно, настраиваемый из Java клиента. И я бы не стал блокировать вызывающий поток из функции Kotlin - нет runBlocking.

@InternalCoroutinesApi
class KotlinClass {
    val coroutineScope = CoroutineScope(Dispatchers.Default)

    interface FlowCallback {
        @JvmDefault
        fun onStart() = Unit

        @JvmDefault
        fun onCompletion(thr: Throwable?) = Unit
        fun onResult(result: Int)
    }

    private fun foo() = flow {
        for (i in 1..3) {
            emit(i)
        }
    }

    fun bar(flowCallback: FlowCallback) {
        coroutineScope.launch {
            foo().onStart { flowCallback.onStart() }
                .onCompletion { flowCallback.onCompletion(it) }
                .collect { flowCallback.onResult(it) }
        }
    }

    fun close() {
        coroutineScope.cancel()
    }    
}

Теперь клиент Java полностью контролирует, как запускать, собирать и отменять поток. Например, вы можете использовать защелку, чтобы дождаться завершения, установить тайм-аут и отменить область действия процедуры. Во-первых, это выглядит как большой код, но обычно вам потребуется такая гибкость.

public class JavaClass {
    public static void main(String[] args) throws InterruptedException {
        CountDownLatch latch = new CountDownLatch(1);
        KotlinClass libraryClass = new KotlinClass();
        libraryClass.bar(new KotlinClass.FlowCallback() {
            @Override
            public void onCompletion(@Nullable Throwable thr) {
                latch.countDown();
            }


            @Override
            public void onResult(int result) {
                System.out.println(result);
            }
        });

        try {
            latch.await(5, TimeUnit.SECONDS);
        } finally {
            libraryClass.close();
        }
    }
}
1 голос
/ 09 марта 2020

Вам не нужно создавать интерфейс в коде Kotlin. Вы можете определить панель так:

 fun bar(callback: (Int) -> Unit) {
     runBlocking {
         foo().collect { callback(it) }
     }
 }

Из кода Java вы можете вызвать функцию следующим образом:

public class JavaClass {

    public static void main(String[] args) {
        KotlinClass libraryClass = new KotlinClass();
        libraryClass.bar(v -> { System.out.println(v); return Unit.INSTANCE; });
    } 
}
...