I have function that must periodically run on the main thread of the application, and for this I use a Handler. The code looks like this:
keepDetecting = true;
final Handler handler = new Handler(Looper.getMainLooper());
Runnable runnable = new Runnable() {
#Override
public void run() {
try{
Utils.log("Detection service is running!");
myFunctionThatMustRunOnMainThread();
}
catch (Exception e) {
Utils.log(e.getClass().getSimpleName() + ": " + e.getMessage());
}
finally{
if(keepDetecting) {
handler.postDelayed(this, DETECTION_INTERVAL);
}
}
}
};
handler.post(runnable);
It works all good as long as the application is visible. However, after pressing the home button, I get the exception message: Handler sending message to a dead thread.
However, I know that the home button does not stop the application, and does not kill the main thead, so what is happening here?
I'm open to other ways to periodically run my function on the main thread, it needs to work if the user presses the home button as well.
EDIT: After further inspection I found that despite the handler throwing this exception once after the home button press, my function keeps getting executed periodically as if nothing happened. So I ended up ignoring this message.
Related
I finally got my app working, i just have one issue which i would like to correct.
I have a button which controls a thread that runs a couple function in the background. The functions in the background eventually stop the thread whenever a certain value is reached. What i am having issues doing is pressing that same button again to just stop the thread manually. Currently I can only start the thread and wait for itself to finish. I am able to do other things in the app, so the thread is running on its own, i just want to kill it manually.
public void onMonitorClick(final View view){
if (isBLEEnabled()) {
if (!isDeviceConnected()) {
// do nothing
} else if (monitorvis == 0) {
showMonitor();
DebugLogger.v(TAG, "show monitor");
//monitorStop = 4;
Kill.runThread(); // I want a function here that would kill the
// thread below, or is there something that
// can be modified in runThread()?
// I did try Thread.Iteruppted() without luck
shutdownExecutor();
} else if (monitorvis == 1) {
hideMonitor();
DebugLogger.v(TAG, "hide monitor");
monitorStop = 0;
runThread(); //The running thread that works great on its own
}
}
else {
showBLEDialog();
}
}
private void runThread() {
new Thread() {
int i;
public void run() {
while (monitorStop != 3) { //This is where the thread stops itself
try {
runOnUiThread(new Runnable() {
#Override
public void run() {
((ProximityService.ProximityBinder) getService()).getRssi();
rssilevel = ((ProximityService.ProximityBinder) getService()).getRssiValue();
mRSSI.setText(String.valueOf(rssilevel) + "dB");
detectRange(rssilevel);
}
});
Thread.sleep(750);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}.start();
}
On first look, you could simply set monitorStop = 3, which would cause the thread to eventually stop after it's timeout completes.
The problem with this, is that I presume if you push the button again or your code modifies monitorStop at some point in the future, then the thead you wanted dead, might stay alive. ie: monitorStop will need to stay equal to three for at least 750ms to assure the thread will comlete it's loop and die.
The correct way to do this would be to create your thread as a new class with it's own monitorStop parameter. When you create the thread, you would keep a reference to it and modify the thread's monitorStop parameter. This way the thread would finish without interruption. If you wanted to create a new thread, then this would not affect the old thread from finishing appropriately.
On executing the following code, i found that the entire app freezes for 10000ms before showing anything on the emulator's screen. I would have expected the first Toast message to appear , followed by the app to freeze for 10000ms and the second toast message to appear. makes me wonder if android piles up all the code in the 'oncreate' method before executing it. is it supposed to be that way?
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toast.makeText(this, new ServiceCode("Hi").s, Toast.LENGTH_SHORT).show();
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
Toast.makeText(this, new ServiceCode("Hello").s, Toast.LENGTH_SHORT).show();
}
It behaves as expected. There is a single thread responsible for UI updates. It's called main thread. This thread shows toast messages too. When you call Toast.show(), Android schedules a new task for the main thread. When main thread is done with onCreate(), it will execute this task and show the toast. But because you blocked main thread for 10 seconds, no toasts are show. There is no one free, who can show this message. But then, 10 seconds later, both toasts will appear one after another, because main thread is free to show them.
Best practice is to never block the main thread. Otherwise your application will freeze and users will see ANR (application nor responding) message. If you need to execute something later in time, you need to post this task to the main thread's task queue for been executed later.
The code below will behave as you expect.
public class MainActivity extends Activity {
private Handler handler = new Handler();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// show first toast immediately
Toast.makeText(this, new ServiceCode("Hi").s, Toast.LENGTH_SHORT).show();
// schedule second toast to appear 10 sec later
handler.postDelayed(new Runnable() {
#Override
public void run() {
Toast.makeText(MainActivity.this,
new ServiceCode("Hello").s, Toast.LENGTH_SHORT).show();
}
}, 10000);
}
}
When an Activity is created, the system-process would send a message to the UI thread of the Activity. The UI thread of the the Activity received the message and then executes "onCreate" method.
Here you make a toast in the "onCreate" method. That will not show the toast immediately. It only sends a message to the message queue of the UI thread. After you UI thread have fininshed the "onCreate" "onStart" "onResume" method, it receives the message of "Toast". At that moment, the Toast is actually showed on the screen.
The reason is simple, the show method of the Toast class might not be a synchronous call "internally", what I mean is, the main-thread is very unlikely to wait until the Toast is actually shown and rendered to continue, hence, it might start a functionality to start rendering the Toast BUT since you immediately after that force the main-thread to stop, it doesn't handle that request since main thread have the highest priority.
Hope it helps!
Regards!
check these links to know about the Android Life-Cycle
http://developer.android.com/training/basics/activity-lifecycle/index.html
Android activity life cycle - what are all these methods for?
your creating a Splash Screen,
if not remove
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
you App won't freeze.
Try this :
Toast.makeText(this, new ServiceCode("Hi").s, Toast.LENGTH_SHORT).show();
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}finally{
Toast.makeText(this, new ServiceCode("Hello").s, Toast.LENGTH_SHORT).show();
}
}
The display of Toast is an asynchronous call.Thus, once the toast request is executed, the operating system jumps to the next operation and meanwhile the toast is prepared and displayed.
In your case since the next operation blocks the UI Thread for 10 sec the toast is not displayed until the UI Thread is released.
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);
At the beginning, I would like to apologize for my bad English.
There is my problem:
Below timer is showing message at every 3 second , but when i getting out from the program (using back button) the message still pop out.
public Runnable mUpdateTimeTask = new Runnable(){
#Override
public void run() {
// TODO Auto-generated method stub
while (true) {
try {
Thread.sleep(3000);}
catch (Exception e) {
// TODO: handle exception
}
mHandler.post(new Runnable(){
#Override
public void run() {
Toast.makeText(getApplicationContext(), "Testing 3 Seconds", Toast.LENGTH_LONG).show();
}
});
}
}
};
i already use mHandler.removeCallbacks(mUpdateTimeTask); still can't stop it.
Thanks in advance.
The call has been made from a runnable thread class, which is still active when Back button is pressed. It will pop messages until the application destroys.
Instead, use this:
handler.removeCallbacksAndMessages(null);
In the docs for removeCallbacksAndMessages it says. here is the link:
developer website documentation link
"Remove any pending posts of callbacks and sent messages whose obj is token. If token is null, all callbacks and messages will be removed."
I recently had the same problem and after searching a lot, I found the solution here.
handler.removeCallbacksAndMessages(null);
would only stop pending messages (Runnables). It won't work for the currently running runnable. You will have to write your own class to stop the currently running runnable.
I have a thread which handles my game loop, when i call .join() on this thread the application stops responding.
I've been trying to fix a problem where the programs never get to the code, I.E the thread never ends.
System.out.println("YAY");
My Thread for the Game Loop:
This thread successfully prints out "Game Ended" but never seems to finish.
Runnable startGameLoop = new Runnable() {//game loop
#Override
public void run() {
AiFactory ai = new AiFactory();
final Button play = (Button) findViewById(R.id.Play);
final Button pass = (Button) findViewById(R.id.Pass);
while(finish==false){
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
currentPlayer = game.getPlayer();
if(currentPlayer.isPlayer()==false){
//System.out.println("passCount:" +game.getPasscount());
ai.decide(nextPlay, game.getPreviousPlayed(), currentPlayer, game.getPasscount() );
if(nextPlay.size()!=0){
runOnUiThread(new Runnable(){
public void run(){
changeArrow();
if(nextPlay.size() ==1){
play1Card();
}
else if(nextPlay.size()==2){
play2Card();
}
else if(nextPlay.size()==3){
play3Card();
}
else if(nextPlay.size()==5){
play5Card();
}
}
}
else{
game.addPassCount();
game.nextTurn();
runOnUiThread(new Runnable(){
public void run(){
changeArrow();
}
});
}
}
else if (currentPlayer.isPlayer()==true){
runOnUiThread(new Runnable(){
public void run(){
changeArrow();
play.setClickable(true);
if(game.getPasscount()==3){
pass.setClickable(false);
}
else{
pass.setClickable(true);
}
}
});
}
}
System.out.println("Game Ended");
}
};
Starting and joining the thread to the main thread:
Thread myThread = new Thread(startGameLoop);
myThread.start();
try {
myThread.join();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("YAY");
}
To my understanding .join() makes the current thread wait till the new thread has finished before carrying on.
Sorry if this is a stupid question, i'm quite new to threading.
When you call myThread.join() inside Activity.onCreate you block the main UI thread. Of course it looks like your application has stopped responding because the UI thread is the one responsible for redrawing UI. All your calls runOnUiThread never happen because your UI thread is busy waiting on your game loop.
Thread.join makes the current thread wait until the thread you call it on ends. It does not cause the thread you call it on to end. So if that thread is never ending (as you say at the top), calling join will make it hang forever.
If you want to actually end the thread, call cancel on it. But that requires your thread to occasionally call isCanceled() and exit its run function if it returns true.
mythread.join() does not ensure that your "mythread" is ended.
You need to place a notify() in your game loop.
...
...
System.out.println("Game Ended");
synchronized(mythread){
mythread.notify();
}
Basically, when you make a call to wait(), the code waits on the thread's monitor, and a call to notify() causes a thread waiting on the object's monitor to wake up.
Also, you can use notifyAll() to wake up all the waiting threads.
Alternatively, you can use timeout version of wait(), where the thread waits either till it gets notified or it times out.