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.
Related
This is a more general question about how to handle the Threads and Loopers in Android, thus the code is a bit generalized.
Consider the following class DoSomethingClass, which has to start some kind of action that needs listening for events (like cellular rssi changes, location changes etc).
public class DoSomethingClass {
private Thread listenForSomethingThread;
private void startDoingSomething() {
listenForSomethingThread = new Thread(new Runnable() {
#Override
public void run() {
Looper.prepare();
SomethingListener listener = new SomethingListener() {
#Override
public void onSomethingHappened(Something something) {
// Quit looper if interrupted
if (Thread.currentThread().isInterrupted()) {
Looper.myLooper().quit();
} else {
// Do stuff with the Something if not
}
}
}
SomethingManager somMan = // Retrieve it
somMan.requestSomethingUpdates(listener);
Looper.loop(); // Blocks until Looper is quitted
somMan.removeSomethingUpdates(listener);
}
});
listenForSomethingThread.start();
}
private void stopDoingSomething() {
listenForSomethingThread.interrupt();
}
}
Pretty simple: When I call startDoingSomething(), a new Thread gets spawned that creates a listener listening for events and handling them (eg. logging, automated yelling at callers etc). For this, it prepares and starts a looper.
When I am finished, I call stopDoingSomething(), which interrupts the Thread: At the next event, nothing will be done, but the Thread will clean up and terminate.
And here's the problem: What if that event never occurs? Then the check for interruption will never be called, the looper will never be quit and will loop forever!?
Is there any way to get a Thread's Looper from another thread, in order to quit it? Or is there a possibility to let it listen for timing intervals in addition to its normal listenees?
I slightly changed your code sample. You can quit the looper like this:
public class DoSomethingClass {
private Thread listenForSomethingThread;
private Looper looper; // create this field
private void startDoingSomething() {
listenForSomethingThread = new Thread(new Runnable() {
#Override
public void run() {
Looper.prepare();
looper = Looper.myLooper(); // store the looper here
SomethingListener listener = new SomethingListener() {
#Override
public void onSomethingHappened(Something something) {
// Quit looper if interrupted
if (Thread.currentThread().isInterrupted()) {
Looper.myLooper().quit();
} else {
// Do stuff with the Something if not
}
}
}
SomethingManager somMan = // Retrieve it
somMan.requestSomethingUpdates(listener);
Looper.loop(); // Blocks until Looper is quitted
somMan.removeSomethingUpdates(listener);
}
});
listenForSomethingThread.start();
}
private void stopDoingSomething() {
looper.quit(); // quit the looper
listenForSomethingThread.interrupt();
}
}
But I guess this looper isn't doing anything because its message queue is not receiving any messages. The listener may be running in the UI thread, which is not what you want, I presume.
I need to understand about the Looper. Looper will consult appropiate handler to to send and process Message and Runnable objects associated with a thread's MessageQueue.
By default, a thread does not have a message loop associated with it, hence doesn’t have a Looper either. To create a Looper for a thread and dedicate that thread to process messages serially from a message loop, you can use the Looper class.
The following is my code I don't invoke Looper explicitly
Thread background2 = new Thread(new Runnable() {
#Override
public void run() {
for ( int i = 0; i < 5; i++) {
final int v =i;
try { Thread.sleep(1000);
handler.post(new Runnable() {
#Override
public void run() {
txt.setText(txt.getText() + "Thread 2 current i : " + String.valueOf(v) +System.getProperty("line.separator"));
}
});
} catch (Exception e) {
Log.v("Error", e.toString());
}
}
}
});
Does it mean that the task/runnable is not put in the queue? what's the difference of above code with this
Thread background3 = new Thread(new Runnable() {
#Override
public void run() {
Looper.prepare();
for ( int i = 0; i < 5; i++) {
final int v =i;
try { Thread.sleep(1000);
handler.post(new Runnable() {
#Override
public void run() {
txt.setText(txt.getText()+ "Thread 3 set : " + String.valueOf(v) +System.getProperty("line.separator"));
}
});
} catch (Exception e) {
Log.v("Error", e.toString());
}
}
Looper.loop();
}
});
both of them accessing a same handler. They both work fine.
Creating a Looper for a Thread means you're setting up that Thread to receive messages from other Threads. Both of your examples are behaving exactly the same because the you're not sending anything to the Thread in the second example. That is, the background3's Looper isn't really being used.
In both examples, you're posting a Runnable to a Handler that was created for the main Thread's Looper. You're not creating that Handler for, e.g., background2. That Handler belongs to the main Thread and its Looper, and anything you post to it will be put into the main queue, and run on the main Thread.
The only difference in your examples is that the second Thread has a Looper, and you could post to it, if you wanted to. To do that, you would create another Handler that belonged to background3's Looper, and post to that. You're not doing that, though, so the second Thread just continues to run without doing anything else.
A Thread doesn't need a Looper simply to post to another Thread's Handler, which is really all that your examples are doing. That other Thread - the main Thread, in this case - has already prepared and started its Looper. You're just sending Runnables to it, and you don't need a Looper of your own to do that.
I'm very new to Android programming so pls excuse my ignorance...
I'm trying to do simple Android app:
User presses a button, starts postDelayed job and then waits on conditional var
after timeout the postDelayer job should signal
private final static long TIMEOUT = 10000;
private Handler mHandler;
final Lock lock = new ReentrantLock();
final Condition condition = lock.newCondition();
#Override
protected void onCreate(Bundle savedInstanceState) {
...
mHandler = new Handler();
...
}
private void timeOutSignal() {
mHandler.postDelayed(new Runnable() {
#Override
public void run() {
Log.d(">> ", "---> timeout notify");
lock.lock();
try {
condition.signal(); // releases lock and waits until doSomethingElse is called
} finally {
lock.unlock();
}
}
}, TIMEOUT);
}
public void buttonClick(View view) {
timeOutSignal();
Log.i("???", "... WAIT");
lock.lock();
try {
condition.await();
} catch (InterruptedException e) {
// todo
} finally {
lock.unlock();
}
Log.i("???", "... WAIT DONE !");
}
What happens is that buttonClick() is stuck waiting and I'm not even seeing the "---> timeout notify" message after timeout...
What I'm doing wrong ?
EDIT: Tried to fix messed up example...
You can't do what you're trying to do. Handlers run on Looper threads. Handlers that are created with the default constructor will use Looper thread that it is currently running in. In this case, it is the main Looper thread (or UI thread). So, you're locking on the UI Thread and the Handler unlocks on the UI Thread, but it will never reach that point because you're blocking the UI Thread.
Also, at no point do I see you actually calling the method that posts to the Handler.
This question already has answers here:
Can't create handler inside thread that has not called Looper.prepare()
(30 answers)
Closed 2 years ago.
I have an Android app running a thread. I want a Toast message to show with a message.
When I do this, I get the below exception:
Logcat trace:
FATAL EXCEPTION: Timer-0
java.lang.RuntimeException: Can't create handler inside thread that has not
called Looper.prepare()
at android.os.Handler.<init>(Handler.java:121)
at android.widget.Toast$TN.<init>(Toast.java:322)
at android.widget.Toast.<init>(Toast.java:91)
at android.widget.Toast.makeText(Toast.java:238)
Is there a work around for pushing Toast messages from threads to the User Interface?
I got this exception because I was trying to make a Toast popup from a background thread.
Toast needs an Activity to push to the user interface and threads don't have that.
So one workaround is to give the thread a link to the parent Activity and Toast to that.
Put this code in the thread where you want to send a Toast message:
parent.runOnUiThread(new Runnable() {
public void run() {
Toast.makeText(parent.getBaseContext(), "Hello", Toast.LENGTH_LONG).show();
}
});
Keep a link to the parent Activity in the background thread that created this thread. Use parent variable in your thread class:
private static YourActivity parent;
When you create the thread, pass the parent Activity as a parameter through the constructor like this:
public YourBackgroundThread(YourActivity parent) {
this.parent = parent;
}
Now the background thread can push Toast messages to the screen.
Android basically works on two thread types namely UI thread and background thread. According to android documentation -
Do not access the Android UI toolkit from outside the UI thread to fix this problem, Android offers several ways to access the UI thread from other threads. Here is a list of methods that can help:
Activity.runOnUiThread(Runnable)
View.post(Runnable)
View.postDelayed(Runnable, long)
Now there are various methods to solve this problem. I will explain it by code sample
runOnUiThread
new Thread()
{
public void run()
{
myactivity.this.runOnUiThread(new runnable()
{
public void run()
{
//Do your UI operations like dialog opening or Toast here
}
});
}
}.start();
LOOPER
Class used to run a message loop for a thread. Threads by default do not have a message loop associated with them; to create one, call prepare() in the thread that is to run the loop, and then loop() to have it process messages until the loop is stopped.
class LooperThread extends Thread {
public Handler mHandler;
public void run() {
Looper.prepare();
mHandler = new Handler() {
public void handleMessage(Message msg) {
// process incoming messages here
}
};
Looper.loop();
}
AsyncTask
AsyncTask allows you to perform asynchronous work on your user interface. It performs the blocking operations in a worker thread and then publishes the results on the UI thread, without requiring you to handle threads and/or handlers yourself.
public void onClick(View v) {
new CustomTask().execute((Void[])null);
}
private class CustomTask extends AsyncTask<Void, Void, Void> {
protected Void doInBackground(Void... param) {
//Do some work
return null;
}
protected void onPostExecute(Void param) {
//Print Toast or open dialog
}
}
Handler
A Handler allows you to send and process Message and Runnable objects associated with a thread's MessageQueue.
Message msg = new Message();
new Thread()
{
public void run()
{
msg.arg1=1;
handler.sendMessage(msg);
}
}.start();
Handler handler = new Handler(new Handler.Callback() {
#Override
public boolean handleMessage(Message msg) {
if(msg.arg1==1)
{
//Print Toast or open dialog
}
return false;
}
});
Here's what I've been doing:
public void displayError(final String errorText) {
Runnable doDisplayError = new Runnable() {
public void run() {
Toast.makeText(getApplicationContext(), errorText, Toast.LENGTH_LONG).show();
}
};
messageHandler.post(doDisplayError);
}
That should allow the method to be called from either thread.
Where messageHandler is declared in the activity as ..
Handler messageHandler = new Handler();
From http://developer.android.com/guide/components/processes-and-threads.html :
Additionally, the Android UI toolkit is not thread-safe. So, you
must not manipulate your UI from a worker thread—you must do all
manipulation to your user interface from the UI thread. Thus, there
are simply two rules to Android's single thread model:
Do not block the UI thread
Do not access the Android UI toolkit from outside the UI thread
You have to detect idleness in a worker thread and show a toast in the main thread.
Please post some code, if you want a more detailed answer.
After code publication :
In strings.xml
<string name="idleness_toast">"You are getting late do it fast"</string>
In YourWorkerThread.java
Toast.makeText(getApplicationContext(), getString(R.string.idleness_toast),
Toast.LENGTH_LONG).show();
Don't use AlertDialog, make a choice. AlertDialog and Toast are two different things.
runOnUiThread(new Runnable(){
public void run() {
Toast.makeText(getApplicationContext(), "Status = " + message.getBody() , Toast.LENGTH_LONG).show();
}
});
this works for me
You can simply use BeginInvokeOnMainThread(). It invokes an Action on the device main (UI) thread.
Device.BeginInvokeOnMainThread(() => { displayToast("text to display"); });
It is simple and works perfectly for me!
EDIT : Works if you're using C# Xamarin
I got this error in a JobService from the following code:
BluetoothLeScanner bluetoothLeScanner = getBluetoothLeScanner();
if (BluetoothAdapter.STATE_ON == getBluetoothAdapter().getState() && null != bluetoothLeScanner) {
// ...
} else {
Logger.debug(TAG, "BluetoothAdapter isn't on so will attempting to turn on and will retry starting scanning in a few seconds");
getBluetoothAdapter().enable();
(new Handler()).postDelayed(new Runnable() {
#Override
public void run() {
startScanningBluetooth();
}
}, 5000);
}
The service crashed:
2019-11-21 11:49:45.550 729-763/? D/BluetoothManagerService: MESSAGE_ENABLE(0): mBluetooth = null
--------- beginning of crash
2019-11-21 11:49:45.556 8629-8856/com.locuslabs.android.sdk E/AndroidRuntime: FATAL EXCEPTION: Timer-1
Process: com.locuslabs.android.sdk, PID: 8629
java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
at android.os.Handler.<init>(Handler.java:203)
at android.os.Handler.<init>(Handler.java:117)
at com.locuslabs.sdk.ibeacon.BeaconScannerJobService.startScanningBluetoothAndBroadcastAnyBeaconsFoundAndUpdatePersistentNotification(BeaconScannerJobService.java:120)
at com.locuslabs.sdk.ibeacon.BeaconScannerJobService.access$500(BeaconScannerJobService.java:36)
at com.locuslabs.sdk.ibeacon.BeaconScannerJobService$2$1.run(BeaconScannerJobService.java:96)
at java.util.TimerThread.mainLoop(Timer.java:555)
at java.util.TimerThread.run(Timer.java:505)
So I changed from Handler to Timer as follows:
(new Timer()).schedule(new TimerTask() {
#Override
public void run() {
startScanningBluetooth();
}
}, 5000);
Now the code doesn't throw the RuntimeException anymore.
I have a thread where I need to periodically perform some checks, get files from the web, and send messages to the main UI thread. I even need to use UI thread parameters (like the map visible area) on each loop of the worker thread. So I suppose that i need to implement bidirectional communication between UIthread and workerThread.
Another problem is that I need to save the identifier of each marker added to the map. I want to save the result of map.addMarker inside my custom array stored in my worker thread. this means that from the uithread, where i update the map, i should tell the workerThread to update the array of markers..
This is a sample of my actual worker thread:
class MyThread extends Thread {
private Handler handler;
private MainActivity main;
public MyThread (MainActivity mainClass, Handler handlerClass) {
this.main=mainClass;
this.handler = handlerClass;
}
#Override
public void run(){
while(true){
sleep(2000);
//do my stuffs
//....
//prepare a message for the UI thread
Message msg = handler.obtainMessage();
msg.obj= //here i put my object or i can even use a bundle
handler.sendMessage(msg); //with this i send a message to my UI thread
}
}
}
My actual problem is that when the UI thread ends processing the message received from the worker thread i should perform an action on the worker thread.
I thought 2 solutions:
1)wait on the worker thread till the message has been processed by the UI thread
2)process the message on the UI thread and then send a message to the worker thread.
I don't know how to do the solution1, so i tried the solution2. I tried adding a looper to my worker thread (RUN sub), this way:
class MyThread extends Thread {
private Handler handler;
private MainActivity main;
public MyThread (MainActivity mainClass, Handler handlerClass) {
this.main=mainClass;
this.handler = handlerClass;
}
#Override
public void run(){
Looper.prepare();
mHandler = new Handler() {
public void handleMessage(Message msg) {
// Act on the message received from my UI thread doing my stuff
}
};
Looper.loop();
while(true){
sleep(2000);
//do my stuffs
//....
//prepare a message for the UI thread
Message msg = handler.obtainMessage();
msg.obj= //here i put my object or i can even use a bundle
handler.sendMessage(msg); //with this i send a message to my UI thread
}
}
}
The problem is that after the Looper.loop() no line of code is executed. I read that this is normal. I read many articles but I didn't understand how should I allow the execution of my while loop, and simultaneously process messages coming from my UI thread.
I hope the problem is clear. Suggest me the best solution.
don't do this:
while(true){
sleep(2000);
it's awfully bad on so many levels. if you need some background processing, use AsyncTasks, if you need a repeating event, use:
private Handler mHandler = new Handler();
private Runnable mSomeTask = new Runnable() {
public void run() {
doSomething();
}
};
and then somewhere in the code:
mHandler.postDelayed(mSomeTask, 100);
this will make your program work faster, jam less resources and basically be a better Android citizen.
I realize this is a very old question, but for periodic task scheduling, use this code:
ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(1);
ScheduledFuture<?> periodicTask = scheduledThreadPool.scheduleAtFixedRate(new Runnable() {
#Override
public void run() {
// do some magic stuff here
// note however, that you're running in background!
Log.d("PeriodicTask", "Doing something....");
}
}, 0 /* initial delay */, 10 /* start every 10 seconds */, TimeUnit.SECONDS);
and when you need to stop the periodic task, just issue
periodicTask.cancel(true);