I am ultimately trying to unit test a custom base adapter, but I am stuck at one point: I am unable to figure out how to get the UI thread to process the message I have just passed to it via sendEmptyMessage(...).
In my Activity I have a "addFoo(Foo foo)" method that updates an array and then calls "sendEmptyMessage(1)", and I have a handleMessage method that calls the ListView's adapter to tell it the data has changed.
I've boiled the unit test down to, roughly:
public void testAddFoo() {
Foo foo = new Foo();
assertTrue(mActivity.addFoo(foo));
assertTrue(mActivity.getHandler().hasMessages(1));
assertFalse(mActivity.getHandler().hasMessages(1));
assertTrue(mActivity.fooListNotEmpty());
}
Naturally it is failing on that assertFalse() (this is a contrived example, simplifying it as best as I can).
What call can I make in to mActivity or its handler or looper to get it to process all pending messages? I have tried some suggestions I've read about calling Looper.loop(), within the UI thread, but those are stabs in the dark and they failed.
FWIW, I'm pretty sure that the handleMessage code is correct because if I call it directly (inside #UiThreadTest) like so:
#UiThreadTest
public void testAddFoo() {
Foo foo = new Foo();
assertTrue(mActivity.addFoo(foo));
Message msg = Message.obtain();
msg.what = 1;
mActivity.handleMessage(msg);
assertTrue(mActivity.fooListNotEmpty());
}
the test ends up working as expected.
If your Activity implements Handler.Callback and you want messages to show up in your handleMessage method, then you need to pass in your Activity when you initialize the Handler in onCreate.
mHandler = new Handler(this);
I know you got the member Handler approach working, but I'm adding this for people like me who show up here trying to figure out how to get the Handler.Callback interface approach working.
If you are implementing Handler.Callback in your activity then you should just do
assertTrue(mActivity.hasMessages(1));
otherwise do not implement the callback and use
mHandler = new Handler() {
// override Handler methods as required
// ie handleMessage(Message msg)
};
and
assertTrue(mActivity.mHandler.hasMessages(1));
Related
When using a background thread to do work, typically you'd update the UI through a Handler.
One way to do this was defining a handler at the class level as outlined in this answer, and this answer
final Handler handler = new Handler(){
#Override
public void handleMessage(Message msg) {
//update UI or call class methods here
}
};
However, this construct would result in the following warning
Handler class should be static otherwise memory leaks might occur
Another way to do this was to use a static inner class as outlined in this answer, and this answer
static class MyHandler extends Handler {
private final WeakReference<Type> myWeakReference;
MyHandler(Type reference) {
myWeakReference = new WeakReference<Type>(reference);
}
#Override
public void handleMessage(Message msg)
{
//Update UI or call class methods here using weak reference
}
}
However, this form of constructor has been Deprecated according to the Android docs.
public Handler ()
This constructor is deprecated. Implicitly choosing a Looper during
Handler construction can lead to bugs where operations are silently
lost (if the Handler is not expecting new tasks and quits), crashes
(if a handler is sometimes created on a thread without a Looper
active), or race conditions, where the thread a handler is associated
with is not what the author anticipated. Instead, use an Executor or
specify the Looper explicitly, using Looper#getMainLooper, {link
android.view.View#getHandler}, or similar. If the implicit thread
local behavior is required for compatibility, use new
Handler(Looper.myLooper()) to make it clear to readers.
How should updating the UI from a Handler be done currently, and should a Handler still be used for this purpose.
As you stated the docs, it says to use Looper.getMainLooper(), just change your code to:
MyHandler(Type reference) {
super(Looper.getMainLooper());
myWeakReference = new WeakReference<Type>(reference);
}
to update the UI from the main/UI thread.
I am attempting to initialize some variables in java and then send them to my native code. I need to delay the nativeactivity call so that the java variables get time to get initialized and then they can be passed to the native activity.
My main problem is that the native activity keeps being called as soon as my activity starts as i have extended my class from NativeActivity(which is compulsory). As soon as onCreate() is called after super my native activity automatically is started and my java variables are not initialized yet.
You can use handler into your class.
Below is my code which is working to perform delay operations:
private void cal(){
final Handler handler2 = new Handler();
Runnable runnable = new Runnable() {
int i=0;
public void run()
{
if(i==0)
{
// Enter your code here which you want run after some deley.
i++;
}
handler2.postDelayed(this, 2000);
}
};
handler2.postDelayed(runnable, 2000);
}
Call this function into your main class.
Hope it will work for you also.
Thanks
I am confuse about the following two ways to initialize the Handler. What's the difference ?
1. First way:
class MyFirstActivity extends Activity {
class Handler mHandler = new Handler();
...
}
2. Second way:
class MySecondActivity extends Activity {
private MyHandler mHandler;
#Oerride
protected void onCreate(Bundle bundle) {
mHandler = new MyHandler(getMainLooper());
}
private final class MyHandler extends Handler {
public MyHandler(Looper looper) {
super(looper, null, true);
}
...
}
}
Note:
I know there is the documentation:
Handler() - Default constructor associates this handler with the Looper for the current thread.
If this thread does not have a looper, this handler won't be able to receive messages so an exception is thrown.
and
Handler(Looper looper) - Use the provided Looper instead of the default one.
It means I want to know more, like
when quit, are there some special operations to do?
Which way is better (or More efficient)?
Thanks~
The Handler (Looper looper) constructor (second way) is used when creating Handler from threads, which do not have default looper, or when you want the handler to run actions on a different thread than your own.
In your "second way" example there is no need to use this type of constructor, the default one will do the same. And as the Activity constructor is invoked on the same thread as onCreate(..) method, two possible initializations ("first" and "second way") of Handler are totally equal.
UPD: make sure not to create inner Handler class.
As per documentation here
Handler() - Default constructor associates this handler with the
Looper for the current thread.
If this thread does not have a looper, this handler won't be able to receive messages so an exception is thrown.
and
Handler(Looper looper) - Use the provided Looper instead of the default one.
Here Looper is Class used to run a message loop for a thread. Check this
It's documented here. Basically second example explicitly tries to get app's main looper, while first one leaves this to the Handler's constructor:
Default constructor associates this handler with the Looper for the
current thread.
Since your both classes are Activities, there's no difference in this particular case.
Is it OK to reuse a Handler object in the next life of Activity which was previously created in its previous session (before onPause, onDestroy()) ?
Like I create a Handler in Activity propagate it to other objects elsewhere, the Activity dies or pauses, then comes to life again and use the old handler ?
// In the oncreate() method I have this code to recreate handler every time
// Then I set the handler to a static Global object
// Other Objects use the global object's static method to get
//fresh handler every timebefore calling sendMessage()
/**
* Set up handler
*/
Handler h = new Handler(new Callback()
{
public boolean handleMessage(Message msg)
{
handleServiceMessage(msg);
return true;
}
});
uiglobal = new UIGlobals(h);
UiGlobals is declared as
private static UIGlobals uiglobal = null;
Not sure if the above approach is correct ..
my GlobalUI class looks like this
public class UIGlobals
{
private static Handler handler = null;
public UIGlobals(Handler h)
{
handler = h;
}
public static Handler getHandler()
{
return handler;
}
}
If you have build your custom Handler class this should work but if you have defined your customized handler in your activity you have to unregister all handler messages in onPause. Otherwise you get a null pointer exception.
But i dont know in whick scenario you need this functionality... I normalley use Handler for UI access but for communication between activity and logic observer pattern.
If your handler is static and the Application (not the activity) hasn't been removed from memory, next time activity starts, static objects will be there.
If your handler is static and the Application has been removed from memory (i.e. service, threads, etc. are all stoped and you exit the only active activity) the next time you start activity, the Aplicationobject will be restarted and static objects will be recreated.
If your handler is not static, the you should be recreating it everytime you create activity, and of course, you will get a new one.
You need to post code or be more specific on your situation, if you want to have a more concrete answer.
For example, if I have a thread doing expensive stuff, and from that thread I want to fire runOnUiThread in the Main (activity) class. Obviously I shouldn't make an instance of my activity class (Main). So if I try
Main.runOnUiThread(mRunnable);
from my thread it gives me an error saying it's not a static method, and therefor it can't be accessed in my way. Now my understanding would be that the activity class is nearly almost accessed in a static way.
How would I do this?
(Btw: I'm doing this because I was getting CalledFromWrongThreadException, Only the original thread that created a view hierarchy can touch it's views)
Raunak has the right idea. I'll just add that you can also specify an integer in the method sendEmptyMessage as an identifier to the handler. This will allow you to create one handler that can handle all of your UI updates, e.g.
public static final int EXAMPLE = 0;
public static final int ANOTHER_EXAMPLE = 1;
private final Handler handler = new Handler(){
#Override
public void handleMessage(Message msg) {
switch( msg.what ){
case EXAMPLE:
//Perform action
break;
case ANOTHER_EXAMPLE;
//Perform action
break;
}
}
}
//Call to submit handler requesting the first action be called
handler.sendEmptyMessage(EXAMPLE);
Hope this helps!
You should use the Handler class. The handler class runs on the UI thread. When you finish work in your thread, call handler.sendEmptyMessage(), from where you can make the changes to your ui.
private final Handler handler = new Handler(){
#Override
public void handleMessage(Message msg) {
// make changes to ui
}
}
Your question doesn't really provide enough details, but from the sound of things, you're in a private inner class (Runnable?) in your activity (Main). If that is the case, you can either write:
Main.this.runOnUiThread(mRunnable);
or
runOnUiThread(mRunnable); //will see that there is no runOnUiThread in the current class and begin looking "upwards"
Also, you may want to look at AsyncTask, specifically at the onPostExecute, onPreExecute and onProgressUpdate callbacks, which run on the UI thread.
first create a runnable outside onCreate. Like this:
private Runnable myRunnable = new Runnable() {
#Override
public void run() {
//work to be done
}
};
and then call the runnable using:
runOnUiThread(myRunnable);
all of the above answers are not very correct.
1)if you want a piece of code to run on UI thread from any thread code base. you can do:
Looper.getMainLooper().post(new Runnable(...))
because Looper.getMainLooper() is a static variable and initialized in ActivityThread.
2) if your runnable code snippet is inside an activity
then you can use:
MainActivity.this.runOnUiThread(...)
For those who are looking for an easy instant solution follow the simple steps
Make a reference of your class before your onCreate() method
MyClass obj;
Initialize it in you onCreate() method
obj = MyClass.this;
Call runOnUiThread()
obj.runOnUiThread(new Runnable() {
public void run() {
//perform your UI tasks here
}
});
Hope it helps.