In one part of my application I post runnable to a Handler, then the code inside run() executes and posts the same runnable to Handler with postDelayed(). This creates something like loop. Is this behaviour achievable with coroutines? I tried to use channel, but I couldn't get it to work.
Is this behaviour achievable with coroutines?
Yes, and in an almost embarrassingly straightforward way:
launch(UI) {
while (!done()) {
// loop body
delay(loopDelayMillis)
}
}
Related
I am making an android game which is made up of a game loop that is constantly running as well as use of the android UI stuff. So they need to be in separate threads to work concurrently.
I am planning to put the game loop inside an AsyncTask however it says in the developer.android documentation that
AsyncTasks should ideally be used for short operations (a few seconds at the most.)
My game loop will in theory be operating indefinitely and almost always for more than a few seconds. Is the asynctask the right place to put this then or is there another preferred method to split up a game loop and the UI operations
AsyncTasks are for short operations only, as the documentation has stated. Also, they usually do some work that shouldn't interfere with the UI. Hence, "Async" and "Task".
What you should use instead is a new Thread. This is called Multi-Threading. There are a lot of Game Frameworks out there which will have problems with android's UI. Though you have not stated what UI Operations you are talking about, but if you plan to use the android's widgets(UI), you could call Activity.runOnUiThread() to run a code on the UI Thread, for example, changing a TextView's text.
Here is a snippet on how you would create a never ending loop in a new thread(or something like this, i dont remember if the function is private):
new Thread(new Runnable() {
#Override
private void run() {
while(true) {
//your code goes here
}
}
});
Although AsyncTask allows you to perform background operations and publish results on the UI thread without having to manipulate threads, it should ideally be used for short operations (a few seconds at the most).
To keep things simple, you could use a Handler, or even better, research about the various APIs provided by the java.util.concurrent package.
import android.os.Handler;
// Create the Handler
private Handler handler = new Handler();
// Define the code block to be executed
private Runnable runnable = new Runnable() {
#Override
public void run() {
// Insert simulation processing code here
// Repeat 60 times per second
handler.postDelayed(this, 1000 / 60);
}
};
// Start the Runnable immediately
handler.post(runnable);
Remember that multi-threading is the easy part. Correct synchronization is hard.
I have some code which uses single HandlerThread with Handler to send messages to it. Is there any way to do this with coroutines? I don't want to create new coroutine every time, I just want to execute blocks of code on the HandlerThread. Please help
If you are looking to execute a block of code in the main Android thread, then you can use UI context from kotlinx-coroutines-android module like this:
launch(UI) {
... // this block of code will be executed in main thread
}
The above snippet sends a message to the main handler to execute your code.
If you looking for a custom handler thread for background work, then you can create a single-threaded context in one of two ways.
Generic approach: Use newSingleThreadedContext() like this:
val ctx = newSingleThreadedContext() // define your context
launch(ctx) { ... } // use it to submit your code there
Android-specific approach: Create new Android Handler, use Handler.asCoroutineDispatcher() extension to convert it to the coroutines context extension. Then you'll be able to use launch to send your blocks of code for execution.
I am using priority job queue , there are number of jobs running in parallel, so that their result populates on UI at same time which takes application to ANR, is there any way , so that i can run asynchronous calls and populate ui synchronously?
UI is always populated synchronously, if it is done in correct way. The correct way is to call activity.runOnUiThread(Runnable), directly or indirectly. Seems that your problem is that your jobs post to UI thread in a too high rate.
First, check if the Runnables to update UI does only UI work. Any calculations should be done outside the UI thread. If it is so, create an intermediate object which makes pauses between UI updates from the parallel jobs and so lets the UI thread to respond to updates from user. It can look as follows:
public class PauseMaker {
Semaphore sem = new Semaphore(1);
public void runOnUiThread(Runnable r) {
sem.aquire();
Thread.sleep(1);
activity.runOnUiThread(new Runnable(){
try {
r();
} finally {
sem.release();
}
});
}
}
You can use the zip operator of rxjava2 to merge the responses together and when the combined response comes you can populate the UI synchronously .. for reference you can check..
http://www.codexpedia.com/android/rxjava-2-zip-operator-example-in-android/
Note The zipper will the return merged response after all the responses are received
I love the convenience of the Handler class; I can easily queue messages and even delay messages. However, all the code runs on the UI thread which is causing stuttering of the animation.
Is there a class, like Handler, that doesn't run on the UI thread ?
You could always use a HandlerThread. I do not have a simple example of this handy, unfortunately.
Personally, I tend to use java.util.concurrent classes directly for things that do not involve the main application thread (e.g., LinkedBlockingQueue, ExecutorService).
I'm a little confused by the currently accepted answer which seems to imply that using Handler on a non-UI thread isn't possible, because it's something I've done quite routinely and I thought it was pretty well known.
Within a non-UI Thread:
#Override
public void run() {
Looper.prepare();
...
mThreadHandler = new Handler() {
public void handleMessage(Message msg) {
switch (msg.what) {
...
break;
default:
break;
}
}
};
Looper.loop();
}
Using the mThreadHandler, messages can be sent to be processed by the Handler in the above non-UI Thread.
If there are any good reasons for not using the Handler / Message classes to post work to be done on a non-UI Thread in this way then I'd like to know. It has been working fine for me so far though. The only reason I've read for not using a Handler in this way is that "a Handler is meant for posting stuff to the UI thread" which is not in itself a good technical basis.
Currently I'm using the following construction:
while(continue)
{
if(somethingChanged)
{
draw();
}
}
Is this way of waiting efficient, or is there a better way to do this?
--
As requested, more info:
I'm drawing on a SurfaceView, with a Thread locking the Canvas and calling the onDraw(Canvas) method. When the thing I have drawn hasn't changed, I don't need to call the onDraw(Canvas) method, so I keep a boolean somethingChanged.
Also, when I touch the screen, I draw let's say a circle at the point of touch, so when I'm touching the screen, somethingChanged is true.
You can also use a wait() and make the other threads notify() this one when something has changed (if the somethingChanged is changed by other threads).
You probably doing a game, I recommend that article: http://dewitters.koonsolo.com/gameloop.html There are very good possible solutions for your request.
Android has a better mechanism regarding idle loops than the std java approach.
It consists of a Looper and a Handler which do the work for you:
Handler myHandler;
...
public void run() {
Looper.prepare(); //this tells Android that your thread will contain a loop
myHandler = new Handler() {
public void handleMessage(Message msg) {
draw();
}
};
Looper.loop; //starts the loop
}
All you have to do to call the draw method is to send a message to that handler instead of setting the boolean var.
Message mess;
myHandler.sendMessage(mess)
That way you can also send any object in that message to the loop, too and android does the thread synchro and message queue stuff for you. And - most importantly - it is efficient, too.
If nothing changed, this is an endless loop that will very probably use 100% cpu, so I'd say that you should at least add some Thread.sleep() calls to give other threads a chance do to something (e.g. changing the value of somethingChanged)
Usually, in infinite loops, you should have some mechanism to avoid it to take over all time of the cpu. This is done, for example, with a sleep. Even a brief sleep will alleviate the use of the processor.
Assuming that this code is in an thread:
while(continue)
{
if(somethingChanged)
{
draw();
}
Thread.sleep( mySleepTime );
}