Related
What does the following exception mean; how can I fix it?
This is the code:
Toast toast = Toast.makeText(mContext, "Something", Toast.LENGTH_SHORT);
This is the exception:
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.<init>(Toast.java:68)
at android.widget.Toast.makeText(Toast.java:231)
You need to call Toast.makeText(...) from the UI thread:
activity.runOnUiThread(new Runnable() {
public void run() {
Toast.makeText(activity, "Hello", Toast.LENGTH_SHORT).show();
}
});
This is copy-pasted from another (duplicate) SO answer.
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.
Look up Communicating with the UI Thread in the documentation. In a nutshell:
// Set this up in the UI thread.
mHandler = new Handler(Looper.getMainLooper()) {
#Override
public void handleMessage(Message message) {
// This is where you do your work in the UI thread.
// Your worker tells you in the message what to do.
}
};
void workerThread() {
// And this is how you call it from the worker thread:
Message message = mHandler.obtainMessage(command, parameter);
message.sendToTarget();
}
Other options:
You could use Activity.runOnUiThread(). Straightforward if you have an Activity:
#WorkerThread
void workerThread() {
myActivity.runOnUiThread(() -> {
// This is where your UI code goes.
}
}
You could also post to the main looper. This works great if all you have is a Context.
#WorkerThread
void workerThread() {
ContextCompat.getMainExecutor(context).execute(() -> {
// This is where your UI code goes.
}
}
Deprecated:
You could use an AsyncTask, that works well for most things running in the background. It has hooks that you can call to indicate the progress, and when it's done.
It's convenient, but can leak contexts if not used correctly. It's been officially deprecated, and you shouldn't use it anymore.
UPDATE - 2016
The best alternative is to use RxAndroid (specific bindings for RxJava) for the P in MVP to take charge fo data.
Start by returning Observable from your existing method.
private Observable<PojoObject> getObservableItems() {
return Observable.create(subscriber -> {
for (PojoObject pojoObject: pojoObjects) {
subscriber.onNext(pojoObject);
}
subscriber.onCompleted();
});
}
Use this Observable like this -
getObservableItems().
subscribeOn(Schedulers.io()).
observeOn(AndroidSchedulers.mainThread()).
subscribe(new Observer<PojoObject> () {
#Override
public void onCompleted() {
// Print Toast on completion
}
#Override
public void onError(Throwable e) {}
#Override
public void onNext(PojoObject pojoObject) {
// Show Progress
}
});
}
----------------------------------------------------------------------------------------------------------------------------------
I know I am a little late but here goes.
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;
}
});
Toast.makeText() can only be called from Main/UI thread. Looper.getMainLooper() helps you to achieve it:
JAVA
new Handler(Looper.getMainLooper()).post(new Runnable() {
#Override
public void run() {
// write your code here
}
});
KOTLIN
Handler(Looper.getMainLooper()).post {
// write your code here
}
An advantage of this method is that you can run UI code without Activity or Context.
Try this, when you see runtimeException due to Looper not prepared before handler.
Handler handler = new Handler(Looper.getMainLooper());
handler.postDelayed(new Runnable() {
#Override
public void run() {
// Run your task here
}
}, 1000 );
I ran into the same problem, and here is how I fixed it:
private final class UIHandler extends Handler
{
public static final int DISPLAY_UI_TOAST = 0;
public static final int DISPLAY_UI_DIALOG = 1;
public UIHandler(Looper looper)
{
super(looper);
}
#Override
public void handleMessage(Message msg)
{
switch(msg.what)
{
case UIHandler.DISPLAY_UI_TOAST:
{
Context context = getApplicationContext();
Toast t = Toast.makeText(context, (String)msg.obj, Toast.LENGTH_LONG);
t.show();
}
case UIHandler.DISPLAY_UI_DIALOG:
//TBD
default:
break;
}
}
}
protected void handleUIRequest(String message)
{
Message msg = uiHandler.obtainMessage(UIHandler.DISPLAY_UI_TOAST);
msg.obj = message;
uiHandler.sendMessage(msg);
}
To create the UIHandler, you'll need to perform the following:
HandlerThread uiThread = new HandlerThread("UIHandler");
uiThread.start();
uiHandler = new UIHandler((HandlerThread) uiThread.getLooper());
Hope this helps.
Reason for an error:
Worker threads are meant for doing background tasks and you can't show anything on UI within a worker thread unless you call method like runOnUiThread. If you try to show anything on UI thread without calling runOnUiThread, there will be a java.lang.RuntimeException.
So, if you are in an activity but calling Toast.makeText() from worker thread, do this:
runOnUiThread(new Runnable()
{
public void run()
{
Toast toast = Toast.makeText(getApplicationContext(), "Something", Toast.LENGTH_SHORT).show();
}
});
The above code ensures that you are showing the Toast message in a UI thread since you are calling it inside runOnUiThread method. So no more java.lang.RuntimeException.
that's what i did.
new Handler(Looper.getMainLooper()).post(new Runnable() {
#Override
public void run() {
Toast(...);
}
});
Visual components are "locked" to changes from outside threads.
So, since the toast shows stuff on the main screen that is managed by the main thread, you need to run this code on that thread.
Hope that helps:)
I was getting this error until I did the following.
public void somethingHappened(final Context context)
{
Handler handler = new Handler(Looper.getMainLooper());
handler.post(
new Runnable()
{
#Override
public void run()
{
Toast.makeText(context, "Something happened.", Toast.LENGTH_SHORT).show();
}
}
);
}
And made this into a singleton class:
public enum Toaster {
INSTANCE;
private final Handler handler = new Handler(Looper.getMainLooper());
public void postMessage(final String message) {
handler.post(
new Runnable() {
#Override
public void run() {
Toast.makeText(ApplicationHolder.INSTANCE.getCustomApplication(), message, Toast.LENGTH_SHORT)
.show();
}
}
);
}
}
runOnUiThread(new Runnable() {
public void run() {
Toast.makeText(mContext, "Message", Toast.LENGTH_SHORT).show();
}
});
Wonderful Kotlin solution:
runOnUiThread {
// Add your ui thread code here
}
first call Looper.prepare() and then call Toast.makeText().show() last call Looper.loop() like:
Looper.prepare() // to be able to make toast
Toast.makeText(context, "not connected", Toast.LENGTH_LONG).show()
Looper.loop()
This is because Toast.makeText() is calling from a worker thread. It should be call from main UI thread like this
runOnUiThread(new Runnable() {
public void run() {
Toast toast = Toast.makeText(mContext, "Something", Toast.LENGTH_SHORT);
}
});
The answer by ChicoBird worked for me. The only change I made was in the creation of the UIHandler where I had to do
HandlerThread uiThread = new HandlerThread("UIHandler");
Eclipse refused to accept anything else. Makes sense I suppose.
Also the uiHandler is clearly a class global defined somewhere. I still don't claim to understand how Android is doing this and what is going on but I am glad it works. Now I will proceed to study it and see if I can understand what Android is doing and why one has to go through all these hoops and loops. Thanks for the help ChicoBird.
For Rxjava and RxAndroid User:
public static void shortToast(String msg) {
Observable.just(msg)
.observeOn(AndroidSchedulers.mainThread())
.subscribe(message -> {
Toast.makeText(App.getInstance(), message, Toast.LENGTH_SHORT).show();
});
}
Coroutine will do it perfectly
CoroutineScope(Job() + Dispatchers.Main).launch {
Toast.makeText(context, "yourmessage",Toast.LENGTH_LONG).show()}
I was running into the same issue when my callbacks would try to show a dialog.
I solved it with dedicated methods in the Activity - at the Activity instance member level - that use runOnUiThread(..)
public void showAuthProgressDialog() {
runOnUiThread(new Runnable() {
#Override
public void run() {
mAuthProgressDialog = DialogUtil.getVisibleProgressDialog(SignInActivity.this, "Loading ...");
}
});
}
public void dismissAuthProgressDialog() {
runOnUiThread(new Runnable() {
#Override
public void run() {
if (mAuthProgressDialog == null || ! mAuthProgressDialog.isShowing()) {
return;
}
mAuthProgressDialog.dismiss();
}
});
}
Java 8
new Handler(Looper.getMainLooper()).post(() -> {
// Work in the UI thread
});
Kotlin
Handler(Looper.getMainLooper()).post{
// Work in the UI thread
}
GL
Handler handler2;
HandlerThread handlerThread=new HandlerThread("second_thread");
handlerThread.start();
handler2=new Handler(handlerThread.getLooper());
Now handler2 will use a different Thread to handle the messages than the main Thread.
To display a dialog or a toaster in a thread, the most concise way is to use the Activity object.
For example:
new Thread(new Runnable() {
#Override
public void run() {
myActivity.runOnUiThread(new Runnable() {
public void run() {
myActivity.this.processingWaitDialog = new ProgressDialog(myActivity.this.getContext());
myActivity.this.processingWaitDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
myActivity.this.processingWaitDialog.setMessage("abc");
myActivity.this.processingWaitDialog.setIndeterminate(true);
myActivity.this.processingWaitDialog.show();
}
});
expenseClassify.serverPost(
new AsyncOperationCallback() {
public void operationCompleted(Object sender) {
myActivity.runOnUiThread(new Runnable() {
public void run() {
if (myActivity.this.processingWaitDialog != null
&& myActivity.this.processingWaitDialog.isShowing()) {
myActivity.this.processingWaitDialog.dismiss();
myActivity.this.processingWaitDialog = null;
}
}
}); // .runOnUiThread(new Runnable()
...
Using lambda:
activity.runOnUiThread(() -> Toast.makeText(activity, "Hello", Toast.LENGTH_SHORT).show());
Toast, AlertDialogs needs to run on UI thread, you can use Asynctask to use them properly in android development.but some cases we need to customize the time outs, so we use Threads, but in threads we cannot use Toast,Alertdialogs like we using in AsyncTask.So we need separate Handler for popup those.
public void onSigned() {
Thread thread = new Thread(){
#Override
public void run() {
try{
sleep(3000);
Message message = new Message();
message.what = 2;
handler.sendMessage(message);
} catch (Exception e){
e.printStackTrace();
}
}
};
thread.start();
}
in Above example i want to sleep my thread in 3sec and after i want to show a Toast message,for that in your mainthread implement handler.
handler = new Handler() {
public void handleMessage(Message msg) {
switch(msg.what){
case 1:
Toast.makeText(getActivity(),"cool",Toast.LENGTH_SHORT).show();
break;
}
super.handleMessage(msg);
}
};
I used switch case here, because if you need to show different message in same way, you can use switch case within Handler class...hope this will help you
This usually happens when something on the main thread is called from any background thread. Lets look at an example , for instance.
private class MyTask extends AsyncTask<Void, Void, Void> {
#Override
protected Void doInBackground(Void... voids) {
textView.setText("Any Text");
return null;
}
}
In the above example , we are setting text on the textview which is in the main UI thread from doInBackground() method , which operates only on a worker thread.
I had the same problem and I fixed it simply by putting the Toast in onPostExecute() override function of the Asynctask<> and it worked.
You need to create toast on UI thread. Find the example below.
runOnUiThread(new Runnable() {
public void run() {
Toast.makeText(activity, "YOUR_MESSAGE", Toast.LENGTH_SHORT).show();
}
});
For displaying Toast message please refer to this article
Here is the solution for Kotlin using Coroutine:
Extend your class with CoroutineScope by MainScope():
class BootstrapActivity : CoroutineScope by MainScope() {}
Then simply do this:
launch {
// whatever you want to do in the main thread
}
Don't forget to add the dependencies for coroutine:
org.jetbrains.kotlinx:kotlinx-coroutines-core:${Versions.kotlinCoroutines}
org.jetbrains.kotlinx:kotlinx-coroutines-android:${Versions.kotlinCoroutines}
Create Handler outside the Thread
final Handler handler = new Handler();
new Thread(new Runnable() {
#Override
public void run() {
try{
handler.post(new Runnable() {
#Override
public void run() {
showAlertDialog(p.getProviderName(), Token, p.getProviderId(), Amount);
}
});
}
}
catch (Exception e){
Log.d("ProvidersNullExp", e.getMessage());
}
}
}).start();
Recently, I encounter this problem - It was happening because I was trying to call a function that was to do some UI stuff from the constructor. Removing the initialization from the constructor solved the problem for me.
I got the same problem and this code is working fine for me now.
As an example this is my code to do a task in the background and UI thread.
Observe how the looper is used:
new Thread(new Runnable() {
#Override
public void run() {
Looper.prepare();
// your Background Task here
runOnUiThread(new Runnable() {
#Override
public void run() {
// update your UI here
Looper.loop();
}
});
}
}).start();
i use the following code to show message from non main thread "context",
#FunctionalInterface
public interface IShowMessage {
Context getContext();
default void showMessage(String message) {
final Thread mThread = new Thread() {
#Override
public void run() {
try {
Looper.prepare();
Toast.makeText(getContext(), message, Toast.LENGTH_LONG).show();
Looper.loop();
} catch (Exception error) {
error.printStackTrace();
Log.e("IShowMessage", error.getMessage());
}
}
};
mThread.start();
}
}
then use as the following:
class myClass implements IShowMessage{
showMessage("your message!");
#Override
public Context getContext() {
return getApplicationContext();
}
}
What does the following exception mean; how can I fix it?
This is the code:
Toast toast = Toast.makeText(mContext, "Something", Toast.LENGTH_SHORT);
This is the exception:
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.<init>(Toast.java:68)
at android.widget.Toast.makeText(Toast.java:231)
You need to call Toast.makeText(...) from the UI thread:
activity.runOnUiThread(new Runnable() {
public void run() {
Toast.makeText(activity, "Hello", Toast.LENGTH_SHORT).show();
}
});
This is copy-pasted from another (duplicate) SO answer.
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.
Look up Communicating with the UI Thread in the documentation. In a nutshell:
// Set this up in the UI thread.
mHandler = new Handler(Looper.getMainLooper()) {
#Override
public void handleMessage(Message message) {
// This is where you do your work in the UI thread.
// Your worker tells you in the message what to do.
}
};
void workerThread() {
// And this is how you call it from the worker thread:
Message message = mHandler.obtainMessage(command, parameter);
message.sendToTarget();
}
Other options:
You could use Activity.runOnUiThread(). Straightforward if you have an Activity:
#WorkerThread
void workerThread() {
myActivity.runOnUiThread(() -> {
// This is where your UI code goes.
}
}
You could also post to the main looper. This works great if all you have is a Context.
#WorkerThread
void workerThread() {
ContextCompat.getMainExecutor(context).execute(() -> {
// This is where your UI code goes.
}
}
Deprecated:
You could use an AsyncTask, that works well for most things running in the background. It has hooks that you can call to indicate the progress, and when it's done.
It's convenient, but can leak contexts if not used correctly. It's been officially deprecated, and you shouldn't use it anymore.
UPDATE - 2016
The best alternative is to use RxAndroid (specific bindings for RxJava) for the P in MVP to take charge fo data.
Start by returning Observable from your existing method.
private Observable<PojoObject> getObservableItems() {
return Observable.create(subscriber -> {
for (PojoObject pojoObject: pojoObjects) {
subscriber.onNext(pojoObject);
}
subscriber.onCompleted();
});
}
Use this Observable like this -
getObservableItems().
subscribeOn(Schedulers.io()).
observeOn(AndroidSchedulers.mainThread()).
subscribe(new Observer<PojoObject> () {
#Override
public void onCompleted() {
// Print Toast on completion
}
#Override
public void onError(Throwable e) {}
#Override
public void onNext(PojoObject pojoObject) {
// Show Progress
}
});
}
----------------------------------------------------------------------------------------------------------------------------------
I know I am a little late but here goes.
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;
}
});
Toast.makeText() can only be called from Main/UI thread. Looper.getMainLooper() helps you to achieve it:
JAVA
new Handler(Looper.getMainLooper()).post(new Runnable() {
#Override
public void run() {
// write your code here
}
});
KOTLIN
Handler(Looper.getMainLooper()).post {
// write your code here
}
An advantage of this method is that you can run UI code without Activity or Context.
Try this, when you see runtimeException due to Looper not prepared before handler.
Handler handler = new Handler(Looper.getMainLooper());
handler.postDelayed(new Runnable() {
#Override
public void run() {
// Run your task here
}
}, 1000 );
I ran into the same problem, and here is how I fixed it:
private final class UIHandler extends Handler
{
public static final int DISPLAY_UI_TOAST = 0;
public static final int DISPLAY_UI_DIALOG = 1;
public UIHandler(Looper looper)
{
super(looper);
}
#Override
public void handleMessage(Message msg)
{
switch(msg.what)
{
case UIHandler.DISPLAY_UI_TOAST:
{
Context context = getApplicationContext();
Toast t = Toast.makeText(context, (String)msg.obj, Toast.LENGTH_LONG);
t.show();
}
case UIHandler.DISPLAY_UI_DIALOG:
//TBD
default:
break;
}
}
}
protected void handleUIRequest(String message)
{
Message msg = uiHandler.obtainMessage(UIHandler.DISPLAY_UI_TOAST);
msg.obj = message;
uiHandler.sendMessage(msg);
}
To create the UIHandler, you'll need to perform the following:
HandlerThread uiThread = new HandlerThread("UIHandler");
uiThread.start();
uiHandler = new UIHandler((HandlerThread) uiThread.getLooper());
Hope this helps.
Reason for an error:
Worker threads are meant for doing background tasks and you can't show anything on UI within a worker thread unless you call method like runOnUiThread. If you try to show anything on UI thread without calling runOnUiThread, there will be a java.lang.RuntimeException.
So, if you are in an activity but calling Toast.makeText() from worker thread, do this:
runOnUiThread(new Runnable()
{
public void run()
{
Toast toast = Toast.makeText(getApplicationContext(), "Something", Toast.LENGTH_SHORT).show();
}
});
The above code ensures that you are showing the Toast message in a UI thread since you are calling it inside runOnUiThread method. So no more java.lang.RuntimeException.
that's what i did.
new Handler(Looper.getMainLooper()).post(new Runnable() {
#Override
public void run() {
Toast(...);
}
});
Visual components are "locked" to changes from outside threads.
So, since the toast shows stuff on the main screen that is managed by the main thread, you need to run this code on that thread.
Hope that helps:)
I was getting this error until I did the following.
public void somethingHappened(final Context context)
{
Handler handler = new Handler(Looper.getMainLooper());
handler.post(
new Runnable()
{
#Override
public void run()
{
Toast.makeText(context, "Something happened.", Toast.LENGTH_SHORT).show();
}
}
);
}
And made this into a singleton class:
public enum Toaster {
INSTANCE;
private final Handler handler = new Handler(Looper.getMainLooper());
public void postMessage(final String message) {
handler.post(
new Runnable() {
#Override
public void run() {
Toast.makeText(ApplicationHolder.INSTANCE.getCustomApplication(), message, Toast.LENGTH_SHORT)
.show();
}
}
);
}
}
runOnUiThread(new Runnable() {
public void run() {
Toast.makeText(mContext, "Message", Toast.LENGTH_SHORT).show();
}
});
Wonderful Kotlin solution:
runOnUiThread {
// Add your ui thread code here
}
first call Looper.prepare() and then call Toast.makeText().show() last call Looper.loop() like:
Looper.prepare() // to be able to make toast
Toast.makeText(context, "not connected", Toast.LENGTH_LONG).show()
Looper.loop()
This is because Toast.makeText() is calling from a worker thread. It should be call from main UI thread like this
runOnUiThread(new Runnable() {
public void run() {
Toast toast = Toast.makeText(mContext, "Something", Toast.LENGTH_SHORT);
}
});
The answer by ChicoBird worked for me. The only change I made was in the creation of the UIHandler where I had to do
HandlerThread uiThread = new HandlerThread("UIHandler");
Eclipse refused to accept anything else. Makes sense I suppose.
Also the uiHandler is clearly a class global defined somewhere. I still don't claim to understand how Android is doing this and what is going on but I am glad it works. Now I will proceed to study it and see if I can understand what Android is doing and why one has to go through all these hoops and loops. Thanks for the help ChicoBird.
For Rxjava and RxAndroid User:
public static void shortToast(String msg) {
Observable.just(msg)
.observeOn(AndroidSchedulers.mainThread())
.subscribe(message -> {
Toast.makeText(App.getInstance(), message, Toast.LENGTH_SHORT).show();
});
}
Coroutine will do it perfectly
CoroutineScope(Job() + Dispatchers.Main).launch {
Toast.makeText(context, "yourmessage",Toast.LENGTH_LONG).show()}
I was running into the same issue when my callbacks would try to show a dialog.
I solved it with dedicated methods in the Activity - at the Activity instance member level - that use runOnUiThread(..)
public void showAuthProgressDialog() {
runOnUiThread(new Runnable() {
#Override
public void run() {
mAuthProgressDialog = DialogUtil.getVisibleProgressDialog(SignInActivity.this, "Loading ...");
}
});
}
public void dismissAuthProgressDialog() {
runOnUiThread(new Runnable() {
#Override
public void run() {
if (mAuthProgressDialog == null || ! mAuthProgressDialog.isShowing()) {
return;
}
mAuthProgressDialog.dismiss();
}
});
}
Java 8
new Handler(Looper.getMainLooper()).post(() -> {
// Work in the UI thread
});
Kotlin
Handler(Looper.getMainLooper()).post{
// Work in the UI thread
}
GL
Handler handler2;
HandlerThread handlerThread=new HandlerThread("second_thread");
handlerThread.start();
handler2=new Handler(handlerThread.getLooper());
Now handler2 will use a different Thread to handle the messages than the main Thread.
To display a dialog or a toaster in a thread, the most concise way is to use the Activity object.
For example:
new Thread(new Runnable() {
#Override
public void run() {
myActivity.runOnUiThread(new Runnable() {
public void run() {
myActivity.this.processingWaitDialog = new ProgressDialog(myActivity.this.getContext());
myActivity.this.processingWaitDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
myActivity.this.processingWaitDialog.setMessage("abc");
myActivity.this.processingWaitDialog.setIndeterminate(true);
myActivity.this.processingWaitDialog.show();
}
});
expenseClassify.serverPost(
new AsyncOperationCallback() {
public void operationCompleted(Object sender) {
myActivity.runOnUiThread(new Runnable() {
public void run() {
if (myActivity.this.processingWaitDialog != null
&& myActivity.this.processingWaitDialog.isShowing()) {
myActivity.this.processingWaitDialog.dismiss();
myActivity.this.processingWaitDialog = null;
}
}
}); // .runOnUiThread(new Runnable()
...
Using lambda:
activity.runOnUiThread(() -> Toast.makeText(activity, "Hello", Toast.LENGTH_SHORT).show());
Toast, AlertDialogs needs to run on UI thread, you can use Asynctask to use them properly in android development.but some cases we need to customize the time outs, so we use Threads, but in threads we cannot use Toast,Alertdialogs like we using in AsyncTask.So we need separate Handler for popup those.
public void onSigned() {
Thread thread = new Thread(){
#Override
public void run() {
try{
sleep(3000);
Message message = new Message();
message.what = 2;
handler.sendMessage(message);
} catch (Exception e){
e.printStackTrace();
}
}
};
thread.start();
}
in Above example i want to sleep my thread in 3sec and after i want to show a Toast message,for that in your mainthread implement handler.
handler = new Handler() {
public void handleMessage(Message msg) {
switch(msg.what){
case 1:
Toast.makeText(getActivity(),"cool",Toast.LENGTH_SHORT).show();
break;
}
super.handleMessage(msg);
}
};
I used switch case here, because if you need to show different message in same way, you can use switch case within Handler class...hope this will help you
This usually happens when something on the main thread is called from any background thread. Lets look at an example , for instance.
private class MyTask extends AsyncTask<Void, Void, Void> {
#Override
protected Void doInBackground(Void... voids) {
textView.setText("Any Text");
return null;
}
}
In the above example , we are setting text on the textview which is in the main UI thread from doInBackground() method , which operates only on a worker thread.
I had the same problem and I fixed it simply by putting the Toast in onPostExecute() override function of the Asynctask<> and it worked.
You need to create toast on UI thread. Find the example below.
runOnUiThread(new Runnable() {
public void run() {
Toast.makeText(activity, "YOUR_MESSAGE", Toast.LENGTH_SHORT).show();
}
});
For displaying Toast message please refer to this article
Here is the solution for Kotlin using Coroutine:
Extend your class with CoroutineScope by MainScope():
class BootstrapActivity : CoroutineScope by MainScope() {}
Then simply do this:
launch {
// whatever you want to do in the main thread
}
Don't forget to add the dependencies for coroutine:
org.jetbrains.kotlinx:kotlinx-coroutines-core:${Versions.kotlinCoroutines}
org.jetbrains.kotlinx:kotlinx-coroutines-android:${Versions.kotlinCoroutines}
Create Handler outside the Thread
final Handler handler = new Handler();
new Thread(new Runnable() {
#Override
public void run() {
try{
handler.post(new Runnable() {
#Override
public void run() {
showAlertDialog(p.getProviderName(), Token, p.getProviderId(), Amount);
}
});
}
}
catch (Exception e){
Log.d("ProvidersNullExp", e.getMessage());
}
}
}).start();
Recently, I encounter this problem - It was happening because I was trying to call a function that was to do some UI stuff from the constructor. Removing the initialization from the constructor solved the problem for me.
I got the same problem and this code is working fine for me now.
As an example this is my code to do a task in the background and UI thread.
Observe how the looper is used:
new Thread(new Runnable() {
#Override
public void run() {
Looper.prepare();
// your Background Task here
runOnUiThread(new Runnable() {
#Override
public void run() {
// update your UI here
Looper.loop();
}
});
}
}).start();
i use the following code to show message from non main thread "context",
#FunctionalInterface
public interface IShowMessage {
Context getContext();
default void showMessage(String message) {
final Thread mThread = new Thread() {
#Override
public void run() {
try {
Looper.prepare();
Toast.makeText(getContext(), message, Toast.LENGTH_LONG).show();
Looper.loop();
} catch (Exception error) {
error.printStackTrace();
Log.e("IShowMessage", error.getMessage());
}
}
};
mThread.start();
}
}
then use as the following:
class myClass implements IShowMessage{
showMessage("your message!");
#Override
public Context getContext() {
return getApplicationContext();
}
}
Can I create onClickListener() for a button in more than 1 threads that are executing simultaneously?
Would that listener be called individually in every thread?
No, a button has only one onClickListener. Setting a second one overwrites any listener set previously. And that function will only be called on the UI thread. You can pass messages to multiple threads from that function though.
There are a lot of ways to communicate between threads. Since you are wondering how to pass something over to the thread, here is a simple example:
public class MainActivity extends AppCompatActivity {
protected void onCreate(Bundle savedInstanceState) {
...
//Start a thread you need to
anotherThread = new AnotherThread();
anotherThread.start();
}
protected void onResume() {
...
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
anotherThread.sendData(message);
}
});
}
}
public class AnotherThread extends Thread {
//Instantiate handler to associate it with the current thread.
//Handler enqueues all tasks in the MessageQueue using Looper
//and execute them upon coming out of queue;
private Handler handler;
#Override
public void run() {
try {
//Here we create a unique Looper for this thread.
//The main purpose of which to keep thread alive looping through
//MessageQueue and send task to corresponding handler.
Looper.prepare();
handler = new Handler() {
#Override
public void handleMessage(Message msg) {
//manage incoming messages here
String value = msg.getData().getString("key");
}
};
Looper.loop();
} catch (Throwable e) {
e.printStackTrace();
}
}
public synchronized void sendData(Message message) {
handler.post(new Runnable() {
#Override
public void run() {
handler.sendMessage(message);
}
});
}
}
To get more about thread communication I'd recommend you the following:
1, 2, 3.
I'm trying to use the UI-Thread, so I've written a simple test activity. But I think I've misunderstood something, because on clicking the button - the app does not respond anymore
public class TestActivity extends Activity {
Button btn;
int i = 0;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
btn = (Button)findViewById(R.id.btn);
btn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
runThread();
}
});
}
private void runThread(){
runOnUiThread (new Thread(new Runnable() {
public void run() {
while(i++ < 1000){
btn.setText("#"+i);
try {
Thread.sleep(300);
}
catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}));
}
}
Below is corrected Snippet of runThread Function.
private void runThread() {
new Thread() {
public void run() {
while (i++ < 1000) {
try {
runOnUiThread(new Runnable() {
#Override
public void run() {
btn.setText("#" + i);
}
});
Thread.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}.start();
}
Just wrap it as a function, then call this function from your background thread.
public void debugMsg(String msg) {
final String str = msg;
runOnUiThread(new Runnable() {
#Override
public void run() {
mInfo.setText(str);
}
});
}
You have it back-to-front. Your button click results in a call to runOnUiThread(), but this isn't needed, since the click handler is already running on the UI thread. Then, your code in runOnUiThread() is launching a new background thread, where you try to do UI operations, which then fail.
Instead, just launch the background thread directly from your click handler. Then, wrap the calls to btn.setText() inside a call to runOnUiThread().
runOnUiThread(new Runnable() {
public void run() {
//Do something on UiThread
}
});
There are several techniques using of runOnUiThread(), lets see all
This is my main thread (UI thread) called AndroidBasicThreadActivity and I'm going to update it from a worker thread in various ways -
public class AndroidBasicThreadActivity extends AppCompatActivity
{
public static TextView textView;
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_android_basic_thread);
textView = (TextView) findViewById(R.id.textview);
MyAndroidThread myTask = new MyAndroidThread(AndroidBasicThreadActivity.this);
Thread t1 = new Thread(myTask, "Bajrang");
t1.start();
}
}
1.) By passing Activity's instance as an argument on worker thread
class MyAndroidThread implements Runnable
{
Activity activity;
public MyAndroidThread(Activity activity)
{
this.activity = activity;
}
#Override
public void run()
{
//perform heavy task here and finally update the UI with result this way -
activity.runOnUiThread(new Runnable()
{
#Override
public void run()
{
AndroidBasicThreadActivity.textView.setText("Hello!! Android Team :-) From child thread.");
}
});
}
}
2.) By using View's post(Runnable runnable) method in worker thread
class MyAndroidThread implements Runnable
{
Activity activity;
public MyAndroidThread(Activity activity)
{
this.activity = activity;
}
#Override
public void run()
{
//perform heavy task here and finally update the UI with result this way -
AndroidBasicThreadActivity.textView.post(new Runnable()
{
#Override
public void run()
{
AndroidBasicThreadActivity.textView.setText("Hello!! Android Team :-) From child thread.");
}
});
}
}
3.) By using Handler class from android.os package
If we don't have the context (this/ getApplicationContext()) or Activity's instance (AndroidBasicThreadActivity.this) then we have to use Handler class as below -
class MyAndroidThread implements Runnable
{
Activity activity;
public MyAndroidThread(Activity activity)
{
this.activity = activity;
}
#Override
public void run()
{
//perform heavy task here and finally update the UI with result this way -
new Handler(Looper.getMainLooper()).post(new Runnable() {
public void run() {
AndroidBasicThreadActivity.textView.setText("Hello!! Android Team :-) From child thread.");
}
});
}
}
If using in fragment then simply write
getActivity().runOnUiThread(new Runnable() {
#Override
public void run() {
// Do something on UiThread
}
});
We use Worker Thread to make Apps smoother and avoid ANR's. We may need to update UI after the heavy process in worker Tread.
The UI can only be updated from UI Thread. In such cases, we use Handler or runOnUiThread both have a Runnable run method that executes in UI Thread.
The onClick method runs in UI thread so don't need to use runOnUiThread here.
Using Kotlin
While in Activity,
this.runOnUiThread {
// Do stuff
}
From Fragment,
activity?.runOnUiThread {
// Do stuff
}
Using Java,
this.runOnUiThread(new Runnable() {
void run() {
// Do stuff
}
});
For fragment use that:
requireActivity().runOnUiThread(() -> {
//your code logic
});
For activity use that:
runOnUiThread(() -> {
//your code logic
});
runOnUiThread is used in a way the UI can be updated with our background thread. For more: https://www.tutorialspoint.com/how-do-we-use-runonuithread-in-android
thy this:
#UiThread
public void logMsg(final String msg) {
new Handler(Looper.getMainLooper()).post(new Runnable() {
#Override
public void run() {
Log.d("UI thread", "I am the UI thread");
}
});
}
You can use from this sample :
In the following example, we are going to use this facility to publish the result from a
synonym search that was processed by a background thread.
To accomplish the goal during the OnCreate activity callback, we will set up
onClickListener to run searchTask on a created thread.
When the user clicks on the Search button, we will create a Runnable anonymous
class that searches for the word typed in R.id.wordEt EditText and starts the
thread to execute Runnable.
When the search completes, we will create an instance of Runnable SetSynonymResult
to publish the result back on the synonym TextView over the UI thread.
This technique is sometime not the most convenient one, especially when we don't
have access to an Activity instance; therefore, in the following chapters, we are
going to discuss simpler and cleaner techniques to update the UI from a background
computing task.
public class MainActivity extends AppCompatActivity {
class SetSynonymResult implements Runnable {
String synonym;
SetSynonymResult(String synonym) {
this.synonym = synonym;
}
public void run() {
Log.d("AsyncAndroid", String.format("Sending synonym result %s on %d",
synonym, Thread.currentThread().getId()) + " !");
TextView tv = (TextView) findViewById(R.id.synonymTv);
tv.setText(this.synonym);
}
}
;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button search = (Button) findViewById(R.id.searchBut);
final EditText word = (EditText) findViewById(R.id.wordEt);
search.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Runnable searchTask = new Runnable() {
#Override
public void run() {
String result = searchSynomim(word.getText().toString());
Log.d("AsyncAndroid", String.format("Searching for synonym for %s on %s",
word.getText(), Thread.currentThread().getName()));
runOnUiThread(new SetSynonymResult(result));
}
};
Thread thread = new Thread(searchTask);
thread.start();
}
});
}
static int i = 0;
String searchSynomim(String word) {
return ++i % 2 == 0 ? "fake" : "mock";
}
}
Source :
asynchronous android programming Helder Vasconcelos
This is how I use it:
runOnUiThread(new Runnable() {
#Override
public void run() {
//Do something on UiThread
}
});
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
gifImageView = (GifImageView) findViewById(R.id.GifImageView);
gifImageView.setGifImageResource(R.drawable.success1);
new Thread(new Runnable() {
#Override
public void run() {
try {
//dummy delay for 2 second
Thread.sleep(8000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//update ui on UI thread
runOnUiThread(new Runnable() {
#Override
public void run() {
gifImageView.setGifImageResource(R.drawable.success);
}
});
}
}).start();
}
Try this: getActivity().runOnUiThread(new Runnable...
It's because:
1) the implicit this in your call to runOnUiThread is referring to AsyncTask, not your fragment.
2) Fragment doesn't have runOnUiThread.
However, Activity does.
Note that Activity just executes the Runnable if you're already on the main thread, otherwise it uses a Handler. You can implement a Handler in your fragment if you don't want to worry about the context of this, it's actually very easy:
// A class instance
private Handler mHandler = new Handler(Looper.getMainLooper());
// anywhere else in your code
mHandler.post(<your runnable>);
// ^ this will always be run on the next run loop on the main thread.
So I'm using this code to show the message "Installing..." while the database is setup with the function 'setUpDB' and is then removed when the database function has completed. This works fine in Gingerbread and honeycomb, but causes the application to crash in ICS
final ProgressDialog pd=ProgressDialog.show(this,"","Installing...");
final Handler handler = new Handler()
{
public void handleMessage(Message msg)
{
if(msg.what==0)
{
pd.dismiss();
}
}
};
//have subcategory heading???
Thread thread = new Thread()
{
#Override
public void run() {
setUpDB();
handler.sendEmptyMessage(0);
}
};
thread.start();
Without dismissing the message, the app will continue to run in ICS (but you can't do anything), and without displaying the message if the user does anything that accesses the database before it is finished being setup it will crash (thus why I need the installing message)..
Okay, here is the code using AsyncTask
final ProgressDialog pd=ProgressDialog.show(this,"","Installing...");
final Handler handler = new Handler()
{
public void handleMessage(Message msg)
{
if(msg.what==0)
{
pd.dismiss();
}
}
};
new databaseInstallTask().execute(handler);
And
private class databaseInstallTask extends AsyncTask<Handler, Void, Handler>
{
#Override
protected Handler doInBackground(Handler... params) {
setUpDB();
return params[0];
}
protected void onPostExecute(Handler handler) {
handler.sendEmptyMessage(0);
}
}
Why don't you try using Asynctask which I suppose is the most appropriate way to handle your case.