``` cameraSource.takePicture({}, { bytes -> det...
# android
v
Copy code
cameraSource.takePicture({}, { bytes -> detectFaces(bytes) })
fun detectFaces(bytes: ByteArray) {
            launch(CommonPool) {

                    val faces = facesClient.detect(bytes.inputStream(), true, false, arrayOf(FaceServiceClient.FaceAttributeType.Age))
                    val results = facesClient.identity("family", faces.map { it.faceId }.toTypedArray(), 4)
                    results.forEach { r ->
                        val name = personMap[r.candidates[0].personId.toString()]
                        Log.i(TAG,"Found $name")
                    }

            }
        }
g
It's hard to follow, not enough context First, do not use CommonPool explicitly
It really depends what API that you use does and how works
Most probably you should just wrap blocking calls to own threads
v
The client in question is from microsoft, and uses just a regular blocking commons http connection under the hood
g
If this request is blocking wrap it to
withContext(<http://Dispatchers.IO|Dispatchers.IO>) {}
This will run this request on special IO dispatcher in a separate thread
v
Is that 0.26 ? I'm using 0.25
g
Yes, 0.26
Use IO in 0.25
v
gonna give it a try, thank you
g
But I would migrate to 0.26, there are significant changes
Also, this is bad style to hide launch in function that returns nothing
Instead use suspend function, do not use launch
Use launch only on most top level of your program
v
I kinda get it, but don't a I need a context to run a suspend function? Oh BTW this was a hack just to print the results, I actually want the function to return the results
I mean rewrite:
suspend fun detectFaces(bytes: ByteArray)
and then call it using
withContext(<http://Dispatchers.IO|Dispatchers.IO>){ detectFaces(...)
is that what you are saying?
g
No, I'm talking about something like that:
Copy code
suspend fun detectFaces(): SomeResult = withContext(IO) {
   //Some blocking code that returns SomeResult
}
And than call it from any coroutine with any context, for example UI without problems and boilerplate
v
Still not working, I think it has to do on how my function gets called
so I have a CameraSource that has a Detector, and a
Tracker
, it seems that the source can create as many Tracker instances as it wants, I first thought the Tracker to be a single instance per CameraSource
so, on the Tracker method I call cameraSource.takePicture (callback)
seems that the Tracker reference gets destroyed before the connection and the suspended function ends
I tried to move all to the Main Activity, but still the same problem happens. Even after declaring the suspended function and the callback as a top level lambda
Copy code
val cameraCallback: (ByteArray) -> Unit = { bytes ->
        GlobalScope.launch(<http://Dispatchers.IO|Dispatchers.IO>) {
            val results = detectFaces(bytes)
            results.forEach {
                Log.i(TAG, "Person: ${personMap[it.candidates[0].personId.toString()]}")
            }
        }
    }
g
What is exactly doesn't work? Your original problem was with NetworkOnMainThread
v
No I said that following that pattern I'm no longer gettting an NetworkOnMainError. Which I really ain't
I'm positive that it has to be due some object being reclaimed by the GC, and the context that holds the thread that was running being destroyed before it finishes
but it's not easy to find out
I simplified my code to run outside of the main activity that was too long
g
seems that the Tracker reference gets destroyed before the connection and the suspended function ends
Sure, because you have callback, so coroutine is destroyd.
v
and the code now works fine using the library
g
Maybe you should just write callback to coroutines adapter for this method
so it will be much easier to use you just call method and suspend until event
It’s hard to recommend something without knowing context and understanding real problem
I’m positive that it has to be due some object being reclaimed by the GC, and the context that holds the thread that was running being destroyed before it finishes
If you keep reference on this object, GC cannot collect it
v
Context: I'm detecting faces on a cameraSource stream, I just got the code from the google vision samples
g
I understand, but need some code to understand what is wrong. Nothing magic how coroutines work with such code. You should have very similar code without coroutines. Coroutine just allow to easily wrap to background thread and use coroutine syntax for callbacks
v
I think the first real problem is that the Detector class creates many instances of a class
Tracker
that is the class with the method that has an event when a face is found
g
Yeah, but it doesn’t look related to coroutines, not sure how this API should work
v
Sure I don't think it's coroutines either, its just a mismatch on how to adapt this code with coroutines. I'll give the adapter a try, done that before (never used coroutines with android, only on ktor)
g
If you have working code without coroutines, I can try to help, it also can help you to understand what is going on there and where is problem. Otherwise not sure what exactly problem with adapting code with coroutines.
v
I don't have a version without coroutines, I was hoping to solve the background thread issue with it. I'll try to get something done with plain threads just for the sake of getting it working, and I'll update the thread, anyway thank you
g
I don’t think that this is problem of threads
You can wrap to coroutines just like to threads
I just thought that you know how this API works
v
Wouldn't make much sense asking for help if I did right? 😉
g
Haa? 😅