Matter of Handlers execution in a sequence - android

I took this snipet from a site explaining handler in Android (a threading thing).
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Thread myThread = new Thread(new Runnable() {
#Override
public void run() {
for (int i = 0; i < 4; i++) {
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (i == 2) {
mUiHandler.post(new Runnable() {
#Override
public void run() {
Toast.makeText(MyActivity.this, "I am at the middle of background task",
Toast.LENGTH_LONG)
.show();
}
});
}
}//ends for()
// THE SECOND HANDLER, RIGHT HERE!
mUiHandler.post(new Runnable() {
#Override
public void run() {
Toast.makeText(MyActivity.this,
"Background task is completed",
Toast.LENGTH_LONG)
.show();
}
});
} //ends run()
});
myThread.start();
Judging from the task outputted in the second executed Handler, which is
Toast.makeText(MyActivity.this,
"Background task is completed",
Toast.LENGTH_LONG)
.show();
Seems like the writer of the article is pretty much sure that the second Handler will be executed last.
My question is that whether it's true that the second Handler will be executed last just after the first Handler finishes its job. Though, when I ran it multiple times, yes, it's executed last. In my mind, since the Handler is done in the background Thread then we're not supposed to know (even predict) which one the those two tasks the Handler will execute first. I need an explanation, thank you in advance.

My question is that whether it's true that the second handler will be
executed last just after the first handler finishes its job.
A Handler instance is associated to a single Thread (also called a message queue).
Runnables are executed on this Thread sequentially.
Calling post() will put the Runnable at the end of that queue, so yes, the second Runnable will be executed after the first one.

The outermost anonymous Runnable, the one passed to the new Thread(...) constructor, is what runs in the background thread. Everything inside that runnable will execute sequentially - one instruction after the other.
Since that runnable has a for loop and only after that the final toast appears you're guaranteed it'll run after the loop body.

There are not two handlers in play, just a single handler on the UI thread (mUiHandler). Your secondary thread is creating Runnable objects and posting them to the Handler. They will be executed by the handler in the order they are posted. Since the loop of the thread executes and posts first then the thread finishes by posting the "second" Runnable, that second one will always execute last, relative to the other things posted within the loop.

Related

Android: Multiple handlers in one Activity

I have a single handler instance, and I try to post two Runnables. But what I observe is only the latest Toast is getting printed on the device.
Handler handler = new Handler(Looper.getMainLooper());
handler.post(new Runnable() {
#Override
public void run() {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
Toast.makeText(getApplicationContext(),"Showing from main activity",
Toast.LENGTH_SHORT).show();
}
});
handler.post(new Runnable() {
#Override
public void run() {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
Toast.makeText(getApplicationContext(),"Showing from main activity new",
Toast.LENGTH_SHORT).show();
}
});
As per the explanation of Handler, it enqueues the runnables into the messages queue of the thread to which it it associated. Which means Both the toast should be displays in the order in which they are enqueued.
Can someone please explain this?
When you make a Handler associated with the main looper, you should keep in mind that it's associated with the main thread. So calling Thread.sleep in the main thread is absolutely discouraged and should be avoided.
Toasts use the UI thread as well, but you prevent it from appearing by freezing this thread. The steps happening in your code are as follow:
The action to show first Toast is enqueued
The action to show second Toast is enqueued
// First action execution
Make the thread sleep for 3
seconds
Showing first toast is enqueued
// Here first Toast should appear, but it doesn't happen right at the moment you called the method. Treat it as another message enqueued in the main looper
Make the thread sleep for 3 seconds
Showing second toast is enqueued
First toast is shown
Second toast is shown
In the end both toasts are shown, but you can see only the last one, because it's shown after the first and covers it. If you want to show two toasts with a short delay, use post delayed method, or something like:
final Handler handler = new Handler(Looper.getMainLooper());
final Context context = getApplicationContext();
handler.post(new Runnable() {
#Override
public void run() {
Toast.makeText(context, "Showing from main activity",
Toast.LENGTH_SHORT).show();
handler.postDelayed(new Runnable() {
#Override
public void run() {
Toast.makeText(context, "Showing from main activity new",
Toast.LENGTH_SHORT).show();
}
}, 3000);
}
});

How to make a periodic code run off the UI thread in Android

The following code is what I'm using currently, but there is an issue that the Toast is being shown, so it probably is in the UI thread isn't it? I do not want the run() function to run on the UI thread as I will probably add some heavy downloading there. However, I want to repeatedly execute this code (after every 9000ms) So what must I do, to either make this run off the UI thread, or a solution to my problem. Thank you.
final Handler handler = new Handler();
Thread feedthread = new Thread()
{
#Override
public void run() {
super.run();
Toast.makeText(context, "UI", Toast.LENGTH_SHORT).show();
handler.postDelayed(this, 9000);
}
};
handler.postDelayed(feedthread, 9000);
Please do not suggest AsyncTask to me unless there is a way to repeat the code without using a while loop wasting resources or setting the thread to sleep. I would like answers to what I asked, and I do not want to run the code on the UI thread.
You need to call the runOnUiThread method to show the Toast
final Handler handler = new Handler();
Thread feedthread = new Thread()
{
#Override
public void run() {
super.run();
runOnUiThread(new Runnable() {
#Override
public void run() {
Toast.makeText(context, "UI", Toast.LENGTH_SHORT).show();
}
});
handler.postDelayed(this, 9000);
}
};
handler.postDelayed(feedthread, 9000);
You want to use the AsyncTask class. Here is an example to show how it works:
// Async Task Class
private class MyTask extends AsyncTask<String, String, String> {
// (Optional) Runs on the UI thread before the background task starts
#Override
protected void onPreExecute() {
super.onPreExecute();
// Do some UI stuff if needed
}
// Runs on a background thread
#Override
protected String doInBackground(String... param) {
String url = param[0];
// Do something with the param, like kick off a download
// You can also use publishProgress() here if desired at regular intervals
/*while (isDownloading) {
publishProgress("" + progress);
}*/
return null;
}
// (Optional) Runs on the UI thread periodically during the background task via publishProgress()
protected void onProgressUpdate(String... progress) {
// Update UI to show progress
/* prgDialog.setProgress(Integer.parseInt(progress[0])); */
}
// (Optional) Runs on the UI thread after the background task completes
#Override
protected void onPostExecute(String file_url) {
// Do some UI stuff to show completion of the task (if needed)
}
}
You can run your task like this:
String url = getInternetUrl();
new MyTask().execute(url);
Java Thread
new Thread(new Runnable(){
private boolean stopped = false;
#Override
public void run(){
while(!stopped) {
// Do, do, do...
try {
Thread.Sleep(9000);
} catch(Exception e){}
}
}
}).start();
Android Handler
Also you can use Android handler class to run a code periodically. This requires you to have a looper-prepared thread to attach the handler to. Basically, a looper-prepared thread is assign a queue and every message posted to this thread will be queued and processed one by one in a queue manner.
This approach has a difference with the former one and is that if your do a lot of work in that background thread so that takes some time, then subsequent queued messages will be processed quicker than the interval (in this case, 9 seconds). Because looper-enabled threads immediately process the next queued message, once they are done with the previous one.
Find More Info Here
Note: You shouldn't [and can't] use this approach as an alternative to Service. This newly created thread does need an underlying component (either Activity or Service) to keep it alive.

Handler postDelayed and Thread.sleep()

I have a thread.sleep and a handler postDelayed in my code:
handler.postDelayed(new Runnable() {
#Override
public void run() {
Log.e(TAG, "I ran");
mIsDisconnect = false;
}
}, DISCONNECT_DELAY);
After the handler code and after the user press the button I have this:
while (mIsDisconnect) {
try {
Thread.sleep(DELAY);
} catch (InterruptedException e) {
Log.e(TAG, "problem sleeping");
}
}
If the user wait long enough I can get the "I ran" in my log. But if the user press the button before the delay is up, it seems that the postDelayed never gets a chance to execute. My question is, does the thread.sleep() mess with the handler postDelayed?
Edit: The purpose of this code is that I want to continue the program only after DISCONNECT_DELAY seconds has already passed. So if the user clicks to early, I have to wait for the elapsed time to finish.
I'm assuming your handler is associated with the same thread the other loop is running on. (A Handler is associated with the thread it is created in.)
postDelayed() puts the Runnable in the handler thread's message queue. The message queue is processed when control returns to the thread's Looper.
Thread.sleep() simply blocks the thread. The control does not return to the Looper and messages cannot be processed. Sleeping in the UI thread is almost always wrong.
To accomplish what you're trying to do, remove the sleep and simply use postDelayed() to post a Runnable that changes your app state (like you already do by setting a member variable mIsDisconnect). Then in the onClick() just check the app state (mIsDisconnect flag) whether it is ok to proceed or not.
I guess that the second section runs on the main thread and you didn't move between threads.
You can't put the main thread on sleep, you stop all UI issues and other stuff that should be run on this thread (the main thread).
Use postDelayed of the handler instead.
The best way is with a sentinel:
runnable = new Runnable() {
#Override
public void run() {
// condition to pass (sentinel == 1)
if (isActive == 0) {
handler.postDelayed(this, 1000); // 1 seconds
}
else {
// isActive == 1, we pass!
// Do something aweseome here!
}
}
};
handler = new Handler();
handler.postDelayed(runnable, 100);

Thread execution on android

I think this is a beginner (me) question, then for you guys is easy to answer.
I have this method:
public void onQuantityTextChange(final int value)
{
new Thread(new Runnable() {
public void run() {
addProductToCart(value);
view.post(new Runnable() {
public void run() {
updateTotals();
}
});
}
}).start();
}
My question is: this peace of code:
view.post(new Runnable() {
public void run() {
updateTotals();
}
is executed only when this addProductToCart(value); method is executed(finished)? or is it more safe to use AsyncTasks with doInBackground() and onPostExecute()?
It is always executed after: addProductToCart(value);
But if that function starts a Thread or AsyncThread or similar then the function will return before that task finishes.
To summarize: nobody can answer without the contents of addProductToCart
That largely depends on whether or not your method addProductToCart(value) starts another thread of its own. If it does, then there's no guarantee as the thread will start and finish as the system sees fit. If not, then you will not call view.post(...) until that thread is complete.
Another thing to watch out for depending on what you're trying to accomplish is the method inside view.post(...) is not guaranteed to run immediately. What this method does is put Runnable objects inside a message queue. This means, this runnable won't execute until the other elements in the message queue execute first. Secondly, the message queue can run at any time meaning even if this is the first Runnable in the queue it will start eventually, but not necessarily immediately.

looper.prepare question

i am trying to loop a toast inside a timer but the toast doesn't show
the log in logcat shows that cannot create handler inside thread that has not called looper.prepare() i am not sure what it means
int initialDelay = 10000;
int period = 10000;
final Context context = getApplicationContext();
TimerTask task = new TimerTask()
{
public void run()
{
try
{
if (a != "")
{
Toast toast = Toast.makeText(context, "Alert Deleted!", Toast.LENGTH_SHORT);
toast.show();
}
}
catch (Exception e)
{
}
}
};
timer.scheduleAtFixedRate(task, initialDelay, period);
what my application does is that every 10 sec it would check if a certain variable is empty. if it is empty then it will show a toast.
i have no problem doing this in a service class but when i try to implement this into
public void onCreate(Bundle savedInstanceState)
i get this error
You're calling it from a worker thread. You need to call Toast.makeText() (and most other functions dealing with the UI) from within the main thread. You could use a handler, for example.
see this answer....
Can't create handler inside thread that has not called Looper.prepare()
You can show this toast in alternative ways also
class LooperThread extends Thread {
public Handler mHandler;
#Override
public void run() {
Looper.prepare();
mHandler = new Handler() {
#Override
public void handleMessage(Message msg) {
// process incoming messages here
}
};
Looper.loop();
}
}
Now as you see this handler is created in normal thread so if you try n send any message from it , it will throw an exception so by bounding it with Looper.prepare() and Looper.loop() you can make any statements executed within it on UI thread
Another Example
Looper allows tasks to be executed sequentially on a single thread. And handler defines those tasks that we need to executed. It is a typical scenario that I am trying to illustrate in example:
class SampleLooper {
#Override
public void run() {
try {
// preparing a looper on current thread
// the current thread is being detected implicitly
Looper.prepare();
// now, the handler will automatically bind to the
// Looper that is attached to the current thread
// You don't need to specify the Looper explicitly
handler = new Handler();
// After the following line the thread will start
// running the message loop and will not normally
// exit the loop unless a problem happens or you
// quit() the looper (see below)
Looper.loop();
} catch (Throwable t) {
Log.e(TAG, "halted due to an error", t);
}
}
}
Now we can use the handler in some other threads(say ui thread) to post the task on Looper to execute.
handler.post(new Runnable()
{
public void run() {`enter code here`
//This will be executed on thread using Looper.`enter code here`
}
});
On UI thread we have an implicit Looper that allow us to handle the messages on ui thread.

Categories

Resources