I have an app with a two threads - main and data loader. When data loader finishes it posts a Runnable object to the main thread (as described in the DevGuide), but it never gets delivered and run.
Here's the basic code:
class MyApp extends Application
{
public void onCreate()
{
LoaderThread t = new LoaderThread();
t.start();
}
private class LoaderThread extends Thread
{
public void run()
{
SystemClock.sleep(2000);
boolean res = m_handler.post(m_runnable);
if(res)
Log.d(TAG, "Posted Runnable");
}
}
private final Handler m_handler = new Handler();
private final Runnable m_runnable = new Runnable() {
public void run()
{
Log.d(TAG, "Hey, i'm runnable!");
}
}
}
Also it maybe important to note that I ran this code as a unit-test derived from an ApplicationTestCase:
class MyAppTest : public ApplicationTestCase
{
public MyAppTest()
{
super(MyApp.class);
}
public void testLoading()
{
createApplication();
// few asserts follow here...
}
}
So this fails. Runnable never gets run() called, although the log indicates that it has been posted successfully. I also tried to send simple messages instead of posting runnable (m_handler.sendEmptyMessage(1) for exa开发者_C百科mple) - they never get delivered to handler's callback in the main thread.
What do I miss here?
Thanks in advance :)
A Handler
requires a Looper
in order to work. The Looper
provides a message queue required by the Handler
.
All instances of Activity
have a Looper
as one is used to process UI Events, but you can create your instance of Looper
elsewhere.
Have a look in your Log output to see if Android is complaining about the absence of a Looper
.
If it is, you might be able to fix by add the following to the top of your onCreate()
method:
Looper.prepare();
m_handler = new Handler();
Looper.run();
And remove the initialisation of m_handler
from later in your code.
Handler
only works in an Activity
AFAIK. You are attempting to use it in an Application
.
An alternative to calling Looper.prepare()
is to call new Handler(Looper.getMainLooper())
. The problem with calling Looper.prepare()
is that it will throw an exception when there is already a looper on your thread. Chances are you are writing code that has to run under different environments and this solution will handle more cases.
See: AsyncTask and Looper.prepare() error
精彩评论