Make Main Thread to Wait for coroutine kotlin - android

I am trying to compress an image in android but and I don't want to use runBlocking.
How can I make the main UI thread to wait for the compression to take place?
Currently, I am doing this
var compressedImage: File? = null
runBlocking {
compressedImage = Compressor.compress(this#UpdateProfileActivity, cachedFile.absoluteFile)
}
camera = "gallery"
//doing something with the compressedImage.
How to do it without runBlocking?

You should not make the main-thread to wait for task completion. It causes freezing of your app until the main-thread gets free. You can do your long-running job in another thread, then switch to the main-thread to do whatever you want.
var compressedImage: File? = null
CoroutineScope().launch(Dispatchers.IO) {
compressedImage = Compressor.compress(this#UpdateProfileActivity, cachedFile.absoluteFile)
withContext(Dispatchers.Main) {
camera = "gallery"
// doing something with the compressedImage.
}
}

Related

How to lock thread correctly with ReentrantLock or Mutex?

I have an acync method with callback:
myAsyncMethod(params) {
handleResult(it)
}
I need to convert it to sync method (block and return result) like this:
val result = mySyncMethod(params)
handleResult(result)
I can't re-implement it by another way because this method provided by third-party library.
I am trying to use ReentrantLock:
fun mySyncMethod(params:Type) {
Log.d("tag", "1")
val result = null
val mutex = ReentrantLock()
myAsyncMethod(params) {
Log.d("tag", "3")
result = it
mutex.unlock()
}
Log.d("tag", "2")
mutex.lock()
Log.d("tag", "4")
return result
}
handleResult(mySyncMethod(params))
I wait that I should see 1, 2, 3, 4. But I get 1, 2, 4, 3 and null in handleResult. I am trying the same with mutex but with the same result. How to make it works?
P.S. Sure I can use synchronized, but in this case I have to use Object-variable additionally.
Here is my code first. I used a thread instead of your method to test myself.
fun main() {
val mutex = ReentrantLock(true)
val asyncCondition = mutex.newCondition()
mutex.lock()
try
{
print(1)
thread {
mutex.lock()
try
{
print(2)
}
finally
{
asyncCondition.signalAll()
mutex.unlock()
}
}
asyncCondition.await()
print(3)
}
finally
{
mutex.unlock()
}
}
Java's ReentrnatLock.lock method will block a thread when it is already locked on the only same thread. Since you are trying to lock an async thread from another thread, your code is not working. To block or release another thread, you may use a Condition like my code.
The reason why I am using try..finallystatement everywhere is that if an exception occurred after locking a thread, you are going to meet the infinity loop, so you must be careful about this case.
You may see these references.
Concurrency (ReentrantLock) in different threads
How do java.util.concurrent.locks.Condition work?
I expect that I should see 1, 2, 3, 4.
Then you misunderstood what ReentrantLock is actually for.
If mySyncMethod can be called from different threads, then after mutex.lock() is called, only one thread at a time can execute the code following mutex.lock() - the other threads executing this method have to wait. Once mutex.unlock() is called, one of the waiting threads will execute the code too and so on.
So, the thread owning the mutex forces the other threads to wait but its own flow isn't blocked. myAsyncMethod starts running after the outer method has completed already and hence result is still null.
I need to convert it to sync method (block and return result) like this:
According to your requirements, you need to block the current thread until the async task is complete. To achieve this, you could use Semaphore or CountDownLatch. For example, with Semaphore, your method could look as follows:
fun mySyncMethod(params:Type) {
Log.d("tag", "1")
val result = null
val semaphore = Semaphore(0)
myAsyncMethod(params) {
Log.d("tag", "3")
result = it
semaphore.release()
}
Log.d("tag", "2")
semaphore.acquireUninterruptibly()
Log.d("tag", "4")
return result
}

How to efficiently show loading dialog if kotlin coroutine job takes quite some time to complete?

What I want to do is to use kotlin coroutines for database operations and show users a loading screen in the meantime. My basic implementation is as follows:
fun loadSomeData(){
mainCoroutineScope.launch {
showLoadingDialog()
// suspening function over Dispatchers.IO, returns list
val dataList = fetchDataFromDatabase()
inflateDataIntoViews(dataList)
hideLoadingDialog()
}
}
This works perfectly for me when the loading takes quite some time for large datasets. But in scenarios where the fetchDataFromDatabase() finishes quickly, showing and hiding the dialog box in quick succession creates an annoying glitching effect.
So what I want is to show the dialog box only if the fetchDataFromDatabase() function take more than, lets say, 100 ms to complete.
So my question is, what is the performance efficient way to achieve this using kotlin coroutines?
Here's an idea:
fun loadSomeData(){
mainCoroutineScope.launch {
val dialogJob = launch {
delay(1000)
try {
showLoadingDialog()
coroutineContext.job.join()
} finally {
hideLoadingDialog()
}
}
val dataList = fetchDataFromDatabase()
inflateDataIntoViews(dataList)
dialogJob.cancel()
}
}
When you cancel the dialogJob, it should either hit the delay statement and prevent showing the dialog, or the join statement, which will cause the finally block to execute and hide it.
Here is how I have achieved this, without using !! not null operator:
val deferred = lifecycleScope.async(Dispatchers.IO) {
// perform possibly long running async task here
}
lifecycleScope.launch (Dispatchers.Main){
// delay showing the progress dialog for whatever time you want
delay(100)
// check if the task is still active
if (deferred.isActive) {
// show loading dialog to user if the task is taking time
val progressDialogBuilder = createProgressDialog()
try {
progressDialogBuilder.show()
// suspend the coroutine till deferred finishes its task
// on completion, deferred result will be posted to the
// function and try block will be exited.
val result = deferred.await()
onDeferredResult(result)
} finally {
// when deferred finishes and exits try block finally
// will be invoked and we can cancel the progress dialog
progressDialogBuilder.cancel()
}
} else {
// if deferred completed already withing the wait time, skip
// showing the progress dialog and post the deferred result
val result = deferred.await()
onDeferredResult(result)
}
}
The main purpose of loading dialog is to prevent user from touching the UI while loading, but there is no guarantee about that. There is always a chance user touches some button before the dialog pops up.
A better way to do this is just disable or hide the UI components, or in general, show a "loading version" of your UI.
It is better to let user cancel the loading instead of setting a short timeout, so you may still need a dialog or snackbar showing a cancel button, or you can make a task manager page in your app, that would be really complicated though.

Limiting the maximum number of coroutines that can run in a scope

I am translating our current application from Java to Kotlin and I came upon this problem.
The java implementation used to use threads to transfer data from the server.
It would create about 100 different threads that would request data, but from what I have seen no more than 4 would run at a time, the others would wait for a thread to finish before starting.
When translating it to Kotlin I used Coroutines
This creates a problem because apparently the server can't handle 100 requests actually being sent.
All coroutines are launched in the same scope , so it's something like this:
//this is a custom scope that launches on Dispatchers.IO + a job that I can use to cancel everything
transferScope.launch {
//loadData is a suspending function that returns true/false
val futures = mDownloadJobs.map{ async { it.loadData() } }
val responses = futures.awaitAll()
//check that everything in responses is true etc....
}
Is there a way to make the specific transferScope to allow only up to 5 coroutines at a time and then when one finishes let a different one run? (I do not care about the order)
If it can't be done through the scope, is there a different way this can be achieved?
Require each coroutine to acquire a Kotlin Semaphore permit from a total of 5 permits before making a request.
Something like this:
import kotlinx.coroutines.sync.Semaphore
val requestSemaphore = Semaphore(5)
val futures = mDownloadJobs.map {
async {
// Will limit number of concurrent requests to 5
requestSemaphore.withPermit {
it.loadData()
}
}
}
val responses = futures.awaitAll()
You can do something like this, group the requests into chunks of 4, launch coroutines to process them and wait till that group is finished before launching a new one.
requests.chunked(4).forEachIndexed { index, chunk ->
coroutineScope {
LOG("processing chunk $index")
chunk.forEach {
launch {
delay(100)
}
}
LOG("done processing $index")
}
}
I believe you should Channel and limit the creation of coroutine that you are creating.
val channel = Channel<Job>()
transferScope.launch {
mDownloadJobs.forEach { channel.send(it) }
channel.close() // don't forget to close the channel
}
coroutineScope {
val responses = mutableListOf<Any>()
repeat(5).map {
launch {
for (job in mDownloadJobsChannel) {
responses.add(jobs.loadData())
}
}
}
}
Parallelization in this case is 5 coroutines.
I did not test this code :D and I am sure there are cleaner ways to do this.
Dispatchers.IO claims to create a thread pool and restrict span out to that pool. It's docstring tells you how to change the pool size (a system property tho).

Actor/message-passing within threaded Game "event loop"

I am building an Android application (using Scala 2.9) and am using a Thread that renders to a SurfaceView; this is for a game so it should update as often as it can. I imagine this issue is similar to other game "event loops" where the input comes from a different thread.
Here is a gross approximation of the current approach that relies on synchronization. It "works well enough", but I have general misgivings about having to use explicit synchronization and "tying up" the View/input thread.
View, "UI thread":
def View.onTouchEvent(e) { // on UI thread
Game.handleInput(e)
}
Game, "Game Thread":
def Game.handleInput(e) = S synchronized { // on UI thread
alterStateBasedOnInput
}
def Game.run () { // on Game thread
while (running) {
S synchronized {
doGameStuff
}
View.post(someStateRelayedViaRunnable)
yield
}
}
Instead of explicitly using synchronization, I'd like to have something like this:
def View.onTouchEvent(e) { // on UI thread
Game.sendMessage(e)
}
def Game.run () { // on Game thread
while (running) {
processMessage
doGameStuff
View.sendMessage(someState) // hopefully same as Game.sendMessage
yield
}
}
Now, this is relatively easy to implement manually using a ConcurrentLinkedQueue or similar, but I would really not like to reinvent the wheel here. In addition, it would be nice to use such an actor/queue to post-back to the UI as well - right now I am using Android's support for posting an (asynchronous) Runnable to the UI thread.
I've briefly looked at several different actor implementations (mainly standard Scala and the Scalaz) and some different Java "message passing" libraries such as Jetlang, but most seem to use implicit threads or a thread executor service. But, in my case I wish to [run the actor and] process messages at a specific time on a specific thread. For View.sendMessage the messages should also be processed on the UI thread, but timing is not as important and can piggyback off of the Runnable execution noted above.
Then, I guess my question is, given the above:
What would be a good - as in "efficient" and idiomatic - approach to feed data between these two threads?
(I am also willing to entertain the suggestion that I completely fail to understand Scala actors and/or Scalaz actors and/or other message passing libraries; Scalaz seems like it might be able to work as I envision, but is hard for me to follow.)
Well, while I would still like to know of a generic/reusable approach to the above, practicality calls. This can also be done by running a Looper on the game thread and then putting the game "event loop stuff" inside the IdleHandler, but I did not like that inversion ..
Here is how I have currently implemented it:
Game/Thread class:
var handler: Handler = _ // handler created on View thread
// Send Message to Looper that exists on View thread
// (Created implicitly for all UI threads.)
def publishEvent(event: OutputEvent) {
handler.obtainMessage(0, event).sendToTarget
}
protected val queue = new ConcurrentLinkedQueue[InputEvent]
def queueEvent(event: InputEvent) { // on UI thread
queue.add(event)
}
def processQueuedEvents() { // on game Thread
#tailrec
def processNextEvent {
val event = queue.poll
if (event ne null) {
doStuffWithInputEvent(event)
processNextEvent
}
}
processNextEvent
}
override def run() { // on game Thread
while (running) {
processQueuedEvents
doOtherGameStuff ~ call_publishEvent ~ etc
}
}
View class:
// Created on UI thread, passed to Game instance
// (The Looper will dispatch Messages to Handlers.)
val handler = new Handler {
override def handleMessage(m: Message) {
val event = m.obj
doStuffWithOutputEvent(event)
}
}
// on UI thread
override def onTouch(v: View, ev: MotionEvent): Boolean = {
// safely queued, will be processed at the start of each game loop
game.queueEvent(InputEvent(..))
}

How to detect UI thread on Android?

Is there a robust way to detect if Thread.currentThread() is the Android system UI thread in an application?
I would like to put some asserts in my model code that asserts that only one thread (eg the ui thread) accesses my state, to assure that no kind of synchronization is necessary.
Common practice to determine the UI Thread's identity is via Looper#getMainLooper:
if (Looper.getMainLooper().getThread() == Thread.currentThread()) {
// On UI thread.
} else {
// Not on UI thread.
}
From API level 23 and up, there's a slightly more readable approach using new helper method isCurrentThread on the main looper:
if (Looper.getMainLooper().isCurrentThread()) {
// On UI thread.
} else {
// Not on UI thread.
}
I think that best way is this:
if (Looper.getMainLooper().equals(Looper.myLooper())) {
// UI thread
} else {
// Non UI thread
}
As of API level 23 the Looper has a nice helper method isCurrentThread. You could get the mainLooper and see if it's the one for the current thread this way:
Looper.getMainLooper().isCurrentThread()
It's practically the same as:
Looper.getMainLooper().getThread() == Thread.currentThread()
but it could be a bit more readable and easier to remember.
public boolean onUIThread() {
return Looper.getMainLooper().isCurrentThread();
}
But it requires API level 23
Besides checking looper, if you ever tried to logout thread id in onCreate(), you could find the UI thread(main thread) id always equals to 1. Therefore
if (Thread.currentThread().getId() == 1) {
// UI thread
}
else {
// other thread
}
Nice extension for Kotlin:
val Thread.isMain get() = Looper.getMainLooper().thread == Thread.currentThread()
So you just call:
Thread.currentThread().isMain
Couldn't you use the runOnUiThread method in the Activity class?See..
http://developer.android.com/reference/android/app/Activity.html#runOnUiThread%28java.lang.Runnable%29

Categories

Resources