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);
}
});
Related
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.
Consider this example:
Thread thread = new Thread(new Runnable() {
public void run() {
// Sleep for 5000ms
// Show toast message
}
});
Now I will start this thread on button click in MainActivity and right after that I would exit the activity on back button press, but in overided method onBackPressed following code is implemented:
If(thread != null)
thread.interupt();
finish();
After few seconds toast message is shown, why is that?
interrupt, clears the interrupt status of your thread and will cause the InterruptedException to be thrown. So if your thread is sleepin, and while it is asleep, you call interrupt, it will be woken up, and the execution flow will continue from the instruction that follows the catch block. Assuming you have something really simple like:
public void run() {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackThreace();
}
runOnUiThread(TOAST);
}
or
public void run() {
while(true) {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackThreace();
}
runOnUiThread(TOAST);
}
}
both will shown the Toast even though you called interrupt()
While blackbelt has already explained the reason why this happens, here is how you can get around the problem.
The best way to interupt a thread is to use a if-boolean-break method.
So if i were to re-write you code it would be along the following lines
onBackPressed:
isBackPressed = true;
inside the thread's run method:
Thread thread = new Thread(new Runnable() {
public void run() {
// Sleep for 5000ms
if(!isBackPressed){
// Show toast message
}
}
});
I make a dialog based on this website http://www.mkyong.com/android/android-progress-bar-example/
When progress bar goes to 100%, dialog closed but a toast still appears continuously. I noticed that after bar goes to 100%, progressHandler still runs looping.
How can I solved this problem?
Thing that I want : When progress bar goes to 100% then dialog closed and Toast shows and closed.
Thread background = new Thread(new Runnable() {
#SuppressWarnings("null")
public void run() {
try {
while (dialog.getProgress() <= dialog.getMax()) {
// wait 500ms between each update
Thread.sleep(100);
// active the update handler
progressHandler.sendMessage(progressHandler.obtainMessage());
}
} catch (java.lang.InterruptedException e) {
// if something fails do something smart
Toast.makeText(getApplicationContext(), "Error Occurs",Toast.LENGTH_LONG).show();
}
}
});
// start the background thread
background.start();
}
// handler for the background updating
Handler progressHandler = new Handler() {
public void handleMessage(Message msg) {
dialog.incrementProgressBy(increment);
if(dialog.getProgress()==100){
editor.putInt("lastestSummaryNoSent",summary.getCurrentSummaryNo());
editor.commit();
dialog.dismiss();
Toast.makeText(getApplicationContext(), "Update Finished", Toast.LENGTH_LONG).show();
}
}
};
This error
Can't create handler inside thread that has not called Looper.prepare()
is because of the Toast you have provided inside the background Thread. Remove the Toast inside the Catch phrase and you will be good to go.
i have two threads one for downloading and other for displaying data there is a cancel button in layout i want when i click cancel button the downloading thread stops how can i do this
final Thread parseThread=new Thread(new Runnable() {
public void run()
{
count=1;
searchResult.clear();
Log.v("url","++"+"http://wap.vinmonopolet.no/vareutvalg/sok?query="+v.getText());
Log.v("searchText","searchText "+ v.getText());
downloader("http://wap.vinmonopolet.no/vareutvalg/sok?query="+v.getText());
//if(msearchCancel)
}
});
parseThread.start();
Thread displayThread = new Thread(new Runnable() {
public void run() {
try {
if(msearchCancel)
parseThread.interrupt();
else
parseThread.join();
}
catch (InterruptedException e)
{
e.printStackTrace();
}
mHandler.post(new Runnable() {
public void run()
{
list_ed=new EfficientAdapter(getApplicationContext());
searchList.setAdapter(list_ed);
progress_waiting1.setVisibility(ProgressBar.GONE);
}
});
}
});
displayThread.start();
First, use AsyncTask for tasks in own threads, it's much easier and handles some low level stuff for you.
Then, in your thread (or background task in AsyncTask), you need periodically to check that main thread requests cancel. In AsyncTask it is isCancelled method.
If you detect cancel request, you exit thread's function ASAP, so that thread may be closed. Otherwise, in case of AsyncTask.cancel, canceling is blocked until background task (thread) gracefully ends.
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.