Hello, I decompiled a java class inside my kmp jar...
# multiplatform
r
Hello, I decompiled a java class inside my kmp jar. But I see some weird things
Copy code
public final Object connectLocal(@NotNull final Credential.LocalMode credential, @NotNull final List features, @NotNull final Function1 configuration, @NotNull Continuation $completion) {
      return FlowKt.callbackFlow((Function2)(new Function2((Continuation)null) {
    ...
};
The last argument isn’t used, but in
callbackFlow
we pass null instead of the completion. Any idea ?
r
Not quite sure why a
null
continuation is provided. However
callbackFlow
itself isn’t a suspend function, therefor it doesn’t accept a continuation (which is why the last argument isn’t used). The
block
parameter of the
callbackFlow
is a suspend function, which is why it should receive a continuation from the
Flow
implementation (I am guessing that that’s probably why you are seeing this continuation argument).
r
Hummm ok, seems logic. But I try to call my function in a Java code. But nothing is happening.
Copy code
XXXX.INSTANCE.connectLocal(
                new Credential.LocalMode(""),
                Feature.Companion.getDefaultFeatures(),
                XXXXHelper.createSessionDefinition(
                        new Server(
                                Server.Scheme.HTTPS,
                                "<http://xxx.com|xxx.com>",
                                Server.Endpoint.defaultOnlineEndpoint()
                        )
                ),
                new Continuation<Flow<? extends InitStep>>() {
                    @NotNull
                    @Override
                    public CoroutineContext getContext() {
                        return EmptyCoroutineContext.INSTANCE;
                    }

                    @Override
                    public void resumeWith(@NotNull Object o) {

                    }
                }
        );
r
Looking at the implementation of
connectLocal
it just returns the
Flow
from
callbackFlow
.
callbackFlow
returns a cold flow, so you would need to collect it before any code inside the
block
is executed.
r
Yes, I do that after
Copy code
if (test instanceof Flow) {
            ((Flow<?>) test).collect(
                    (FlowCollector<Object>) (o, continuation) -> null,
                    new Continuation<Unit>() {
                        @NotNull
                        @Override
                        public CoroutineContext getContext() {
                            return EmptyCoroutineContext.INSTANCE;
                        }

                        @Override
                        public void resumeWith(@NotNull Object o) {
                            System.out.println(o);
                        }
                    }
            );
        }
But nothing is printed
r
Do you have the Kotlin code for the
connectLocal
functions? I am starting to wonder why it accepts a continuation if it returns the Flow directly 🤔
r
I did it, so yeah 😄
Copy code
suspend fun connectLocal(
		credential: Credential.LocalMode,
		features: List<Feature> = Feature.getDefaultFeatures(),
		configuration: LocalSessionConfiguration.() -> Unit
	): Flow<InitStep> = callbackFlow {
		val uuid = EPPlatform.randomUUID()
		val config = LocalSessionConfiguration().apply(configuration)
		val parentJob = Job() // improve for better error handling -> Todo for later
		val session = Session.create(uuid, SessionMode.LOCAL)
		val scope = session.scope
		val client: HttpClient = buildClient(
			config = config, localConfiguration = config.localConfiguration
		)

		scope.declare(client)
		koinApp.koin.declare(LoginAndSessionService(client = client))
		scope.baseDI(client = client)

		val sortedFeatures = scope.initFeatures(features, client, config)

		scope.get<GatewayRepository>()
			.setLocalToken(credential.token)
			.exceptionOrNull()

        trySend(InitStep.Authenticated)
        initFetchFeatures(sortedFeatures, scope, config.mode, parentJob).join()
        success(session = session, startPoller = config.startPoller)
        awaitClose { parentJob.complete() }
    }
r
Alright. Where is your
test
variable comming from? Could you verify if
resumeWith
for your
connectLocal
call is being called with a Flow? Also is the code inside the
callbackFlow
ever called?
r
test
variable is just the return of
connectLocal
. I don’t how to verify, I can put break point inside the decompiled class. Yeah, the method is working in a Android App
r
I would try and print
test
to verify you are actually receiving the Flow. If test is indeed the Flow then I think the only remaining issue is in the other print statement. You are currently printing the result of the
collect
. Which is probably not going to be called (I don't see any
close
call inside the
callbackFlow
). Try logging
o
from the first argument (
FlowCollector
).
Also it might be worth checking the coroutines rx libraries: https://github.com/Kotlin/kotlinx.coroutines/tree/master/reactive/kotlinx-coroutines-rx3
r
test = block[kotlinx.coroutines.channels.ProducerScope<com.modulotech.epos.session.InitStep>.() -> kotlin.Unit] -> CallbackFlowBuilder[capacity=-2]
The flow collector is not called, nothing is print out. I would like to stay full kotlin.
r
Hmm that's not what I would expect from a Flow type. How about the
o
inside
resumeWith
of the
connectLocal
call?
r
test instanceOf Flow
is
true
. I have put in every
resumeWith
a println, but nothing is printed. Maybe it’s because it’s not launch in a Coroutine ?
r
Yeah these things are tricky. If you don't want to use something like rx, you could create a "wrapper function" in Kotlin that collects the flow and invokes a callback instead:
Copy code
fun connectLocal(...., onItem: (InitStep) -> Unit) {
    coroutineScope.launch {
        connectLocal(....).collect { onItem(it) }
    }
}
r
I really don’t want to go that way, but seems like I have no choice... The module is based on coroutine, so if I can find a way to make it work, it would be better. Thank’s for helping