https://kotlinlang.org logo
#android
Title
# android
v

Vinicius Carvalho

09/24/2018, 1:54 PM
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

gildor

09/24/2018, 2:39 PM
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

Vinicius Carvalho

09/24/2018, 2:44 PM
The client in question is from microsoft, and uses just a regular blocking commons http connection under the hood
g

gildor

09/24/2018, 2:45 PM
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

Vinicius Carvalho

09/24/2018, 2:46 PM
Is that 0.26 ? I'm using 0.25
g

gildor

09/24/2018, 2:46 PM
Yes, 0.26
Use IO in 0.25
v

Vinicius Carvalho

09/24/2018, 2:47 PM
gonna give it a try, thank you
g

gildor

09/24/2018, 2:47 PM
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

Vinicius Carvalho

09/24/2018, 2:50 PM
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

gildor

09/24/2018, 3:17 PM
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

Vinicius Carvalho

09/24/2018, 11:09 PM
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

gildor

09/25/2018, 12:50 AM
What is exactly doesn't work? Your original problem was with NetworkOnMainThread
v

Vinicius Carvalho

09/25/2018, 2:22 AM
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

gildor

09/25/2018, 2:24 AM
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

Vinicius Carvalho

09/25/2018, 2:24 AM
and the code now works fine using the library
g

gildor

09/25/2018, 2:24 AM
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

Vinicius Carvalho

09/25/2018, 2:26 AM
Context: I'm detecting faces on a cameraSource stream, I just got the code from the google vision samples
g

gildor

09/25/2018, 2:27 AM
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

Vinicius Carvalho

09/25/2018, 2:27 AM
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

gildor

09/25/2018, 2:28 AM
Yeah, but it doesn’t look related to coroutines, not sure how this API should work
v

Vinicius Carvalho

09/25/2018, 2:29 AM
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

gildor

09/25/2018, 2:30 AM
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

Vinicius Carvalho

09/25/2018, 2:35 AM
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

gildor

09/25/2018, 2:50 AM
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

Vinicius Carvalho

09/25/2018, 1:15 PM
Wouldn't make much sense asking for help if I did right? 😉
g

gildor

09/25/2018, 1:26 PM
Haa? 😅
3 Views