我开发了一个小型的Android应用程序,它使用AlarmManager来调用Handler Thread,它将来自移动设备的某些信息与远程服务器同步。这个过程每15分钟发生一次。
当我在没有AlarmManager的帮助下使用HandlerThread时,始终的所有内容都可正常工作。但是,当我尝试将这两者结合使用时,有时它可以正常工作,有时我收到以下错误:
W/System.err(10557): java.lang.NullPointerException
W/System.err(10557):at Synchronizer.queueSyncEverything(Synchronizer.java:109)
W/System.err(10557): at SyncService.onHandleIntent(SyncService.java:33)
W/System.err(10557): at android.app.IntentService$ServiceHandler.handleMessage(IntentService.java:65)
W/System.err(10557): at android.os.Handler.dispatchMessage(Handler.java:99)<BR/>
W/System.err(10557): at android.os.Looper.loop(Looper.java:137)
W/System.err(10557): at android.os.HandlerThread.run(HandlerThread.java:60)
代码非常简单,您可以在以下代码段中看到:
//Method from SyncService, a class which extends IntentService
protected void onHandleIntent(Intent intent) {
ConnectivityManager cm = (ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE);
if(cm.getActiveNetworkInfo() == null){
return;
}
if(mSynchronizer == null){
mSynchronizer = new Synchronizer(getApplicationContext(), this);
mSynchronizer.start();
mSynchronizer.getLooper();
}
mSynchronizer.queueSyncEverything();
}
//Method from Synchronizer, a class which extends HandlerThread
public void queueSyncEverything(){
try{
mHandler.obtainMessage(MESSAGE_SYNC_EVERYTHING).sendToTarget();
}
catch(Exception e){
mListener.onError();
e.printStackTrace();
}
}
我已经检查过Handler或Looper是否为null,但它们都没问题。
修改 正如@DavidWasser建议的那样,我做了一些测试,发现有时mHandler是null。这个变量在Synchronizer的方法onLooperPrepared中设置(从HandlerThread扩展),如下所示:
@Override
protected void onLooperPrepared(){
mHandler = new Handler(){
@Override
public void handleMessage(Message msg){
if(msg.what == MESSAGE_SYNC_EVERYTHING){
handleSyncEverything();
mListener.onFinished();
}
}
};
}
这个类的构造函数,正如@DavidWasser所问,只是:
public Synchronizer(Synchronizer.Listener listener){
super(TAG);
mListener = listener;
}
mListener只是一个类似委托的对象,它接收Synchronizer类发送的事件,就像同步完成时一样。 TAG只是一个名称,使其更容易调试。也许我的主要困难是了解HandlerThread类的工作原理以及何时是设置其Handler对象的正确时间。
P.S。:通过阅读“Android编程:大书呆子牧场指南”这本书,我设置了HandlerThread。
答案 0 :(得分:0)
请勿在{{1}}中初始化mHandler
,因为在onLooperPrepared()
调用后,此方法可以被称为。这是一个可以咬你的小时间窗口。
而是在getLooper()
中创建一个方法,如下所示:
Synchronizer
并在public void createHandler() {
mHander = new Handler(getLooper()) {
@Override
public void handleMessage(Message msg){
if(msg.what == MESSAGE_SYNC_EVERYTHING){
handleSyncEverything();
mListener.onFinished();
}
}
};
}
中调用此方法,而不是调用onHandleIntent()
。
这将确保mSynchronizer.getLooper()
在<{>> 之前初始化 mHandler
。
注意:您根本不需要覆盖queueSyncEverything()
。