I am invoking a method:
method = (MessageController.getInstance()).getClass().getMethod(data.getString("action") + "Action", cArg);
method.invoke(MessageController.getInstance(), "param1");
and the method:
public static void errorAction(String data){
ProgressDialog dialog = new ProgressDialog(context);
dialog.setTitle("hi");
dialog.setMessage("there");
dialog.show();
}
However i get the following exception:
Caused by: java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
on the dialog.show() part.
Is this because of invoking actually happens on a new thread?
If yes, how to make it run on UI thread? How to just show the dialog?
Thanks!
I'm not exactly sure why you're using reflection to do this, but yes. The reason is you're not on a Looper when invoking the show() method. More likely, you'll get another error if it isn't on the main looper thread (UI thread).
Handlers and Loopers go hand-in-hand. A Looper keeps a thread alive and running and a Handler executes Runnables and posts Messages on that thread.
So, to post to a main thread, you can create a new Handler yourself and pass in the main Looper which will ensure it gets executed on the main thread:
new Handler(Looper.getMainLooper()).post(new Runnable() {
#Override
public void run() {
// Code to execute on the main thread.
}
}
Doing it this way doesn't require an Activity or View. It will always post on the UI thread and not another Looper thread that you created. Note that this asynchronous and won't execute until the next draw pass.
Or you can run it in the UI thread, like so:
getActivity().runOnUiThread(new Runnable() {
#Override
public void run() {
method = (MessageController.getInstance()).getClass().getMethod(data.getString("action") + "Action", cArg);
method.invoke(MessageController.getInstance(), "param1");
}
});
Related
In Play Console I see users get an IllegalStateException in the sendMessage chromecast call. According to the API:
IllegalStateException: If this method is not called on the main thread.
However in my code I call it in the following way:
Handler uiHandler = new Handler(Looper.getMainLooper());
uiHandler.post(new Runnable(){
#Override
public void run() {
mCastSession.sendMessage(mMyChannel.getNamespace(), message);
}
});
What could be the problem here? I cannot reproduce it myself.
Try putting a Log.d() inside the body of run() where you make sure the flow gets there and you can rule out that the error is in the sendMessage() method processing. Then:
runOnUiThread
Runs the specified action on the UI thread. If the current thread is
the UI thread, then the action is executed immediately. If the current
thread is not the UI thread, the action is posted to the event queue
of the UI thread.
Handler() and runOnUiThread() can perform operations on the Thread UI, but runOnUiThread() only executes a process from a thread, and in addition a reference to the activity in which it is executed must be passed.
runOnUiThread(new Runnable() {
public void run() {
//...
}
});
GL
Source
There are different methods posted on the web on how to run code on the UI thread. They all accomplish the same task, however, I really want to know the difference between these methods.
Method 1:
new Handler(Looper.getMainLooper()).post(new Runnable() {
#Override
public void run() {
// Code here will run in UI thread
}
});
Method 2:
new Handler().post(new Runnable() {
#Override
public void run() {
// Code here will run in UI thread
}
});
Method 3:
runOnUiThread(new Runnable() {
#Override
public void run() {
// Code here will run in UI thread
}
});
In Android, a Thread might have one Looper or MessageQueue. Handler is used to send Message or post Runnable to MessageQueue of a Thread, and it must always be associated with a Looper or a MessageQueue of a Thread.
Method 1
new Handler(Looper.getMainLooper()).post(new Runnable() {
#Override
public void run() {
// Code here will run in UI thread
}
});
When open an app, Android create a new thread (called main thread or UI thread) with a Looper and MessageQueue, this thread is used to render UI and process input events from users.
The above code is create a Handler and associated with Looper of UI thread, so the runnable will be queued to MessageQueue of UI thread, and will be executed later.
Method 2
new Handler().post(new Runnable() {
#Override
public void run() {
// Code here will run in UI thread
}
});
Creating a Handler and associated with Looper of current thread, there are 3 cases:
If this code is executed on UI thread, then the runnable will be queued to MessageQueue of UI thread and will be executed later.
If this code is executed on a background thread, if this thread has a Looper, then the runnable will be queued to MessageQueue of background thread and will be executed later.
If this code is executed on a background thread and this thread has no Looper, then an exception will be thrown.
Method 3
runOnUiThread(new Runnable() {
#Override
public void run() {
// Code here will run in UI thread
}
});
runOnUiThread is just a utility method of Activity, it used when you want to execute some code on UI thread. The logic behind this method is if current thread is UI thread, then execute it immediately, otherwise used Handler to post a message to MessageQueue of UI thread (like method 1).
Method 1 will always work.
Method 2 will only work if you're already on the UI thread- the new Handler without a Looper parameter creates a Handler to the current thread (and fails if there is no Looper on the current thread).
Method 3 needs to be done in an Activity or called on an Activity object, as runOnUiThread is a function of Activity. But under the hood it will do the same as 1 (although probably keeps a single Handler around to be more efficient, rather than always new-ing one).
All methods works like this:
Method 1 looping handler if loop exist
Method 2 handler can works in all activities if not private or wanted
Method 3 handler can work only in current activity
Please I am blocked with this concept of Handlers and Runnables in Android. Can someone please give me detailed explanation on Handlers and Runnables? Their syntax and implementation? I have read many articles on this but the concepts are not still clear and are even deployed in Java. Thanks in advance
I'm going to try to simplify so bear with me if it is not 100% accurate.
Basically, a Handler is used to communicate with a MessageQueue associated with a Thread.
If you're on the main thread, or if you've called Looper.prepare() in the Thread that you're in, it has a Looper which is basically a holder for the MessageQueue.
This queue is constantly polled so that whenever a Message goes into it, it's dealt with on the Thread associated with this MessageQueue
If you're trying to execute a piece of code on a particular Thread, you have to use a Runnable. It is just an interface that has a void run() method which will be executed by the Looper, on its Thread.
Let's say you're doing a network request, you want it to happen on another Thread but when you get the result you somehow need to pass the data back to the Main Thread in order to update your UI because Views can't be modified from another Thread.
You would do it like so:
// This will let you run method on main thread (even if you're not on main thread)
private final Handler handler = new Handler(Looper.getMainLooper());
// This will let you run method on background thread
private final Executor executor = Executors.newSingleThreadExecutor();
public void doSomething() {
// posting to executor will go to background thread
executor.post(new Runnable() {
#Override
public void run() {
// This will now run on background thread
// you can for example do network request here
// posting to handler will go back to main thread
handler.post(new Runnable() {
#Override
public void run() {
// This will execute on the Main Thread
}
});
}
});
}
I am trying to use an SDK that seems to need to create a handler into my service.
A error message appeared saying that I can't create handler if the thread has not called Looper.prepare(), so I do call Looper.prepare() and this problem disappear.
However, this service need to start an activity after a while, and this Looper.prepare() seems to be messing with it, as the first UI function crash saying that it cannot be called from a non-ui thread.
I am a bit confused about why this is happening, and the research I made on thread and looper didn't help me. I get why we cannot create a handler if a looper does not exist on the thread, but not why creating a looper prevent me from using the ui thread afterward.
Below my code simplified :
public class MyService extends Service implement SDKCallback{
...
void callSDK(){
Looper.prepare();
SDK.run(); //Does thing I don't know about
}
#Override
SDKCallback(){
startActivity(new Intent(this, MyActivity.class);
}
}
You dont have to call Looper.prepare(). Try this code to create Handler,
new Handler(Looper.getMainLooper()) {
#Override
public void handleMessage(Message message) {
}
};
If you put Looper.prepare() in your worker thread, it will solve your first crash problem [the thread has not called Looper.prepare()]. But its not in UI thread, so you cant start next Activity.
What this above code does is, it creates the Handler in UI thread. So you can start next Activity.
Edit: Try this.
#Override
SDKCallback(){
new Handler(Looper.getMainLooper()) {
#Override
public void handleMessage(Message message) {
startActivity(new Intent(MyService.this, MyActivity.class));
}
};
}
I have some code that interacts with the Android Facebook SDK, Asynchronously. Unfortunately this means when it returns it is in a background thread.
Cocos-2dx prefers me to interact with it in the Main Thread, especially when doing things like telling the Director to switch scenes (As it involves Open GL)
Is there any way to get some code to run on the Main thread ?
As long as you have a Context, you can do something like this:
Handler mainHandler = new Handler(context.getMainLooper());
And to run code on UI thread:
mainHandler.post(new Runnable() {
#Override
public void run() {
// run code
}
});
As suggested by kaka:
You could also use the static Looper.getMainLooper() which
Returns the application's main looper, which lives in the main thread of the application.
runOnUiThread(new Runnable() {
#Override
public void run() {
//execute code on main thread
}
});
In C++:
Director::getInstance()->getScheduler()->performFunctionInCocosThread([]{
// execute code on main thread
});
You can run code in the main thread in this 2 ways: (with Java 8's lambdas)
If you have an activity instance:
activity.runOnUiThread(() -> {
// do your work on main thread
});
Otherwise use an Handler object and post a Runnable.
You can use the postDelayed version if you need some delay before executing the code.
Handler handler = new Handler(Looper.getMainLooper());
handler.post(() -> {
// do your work on main thread
});