在死线程上向处理程序发送消息

时间:2013-06-21 14:28:14

标签: android

我正在开发一种后台服务,在一段时间内对服务器进行轮询。关键是:我有一个调用另一个服务的IntentService(称为NotificationsService),但是这个请求的响应没有回来。并在logcat中出现:

06-19 05:12:00.151: W/MessageQueue(6436): Handler (android.os.Handler) {416659f0} sending message to a Handler on a dead thread
06-19 05:12:00.151: W/MessageQueue(6436): java.lang.RuntimeException: Handler (android.os.Handler) {416659f0} sending message to a Handler on a dead thread
06-19 05:12:00.151: W/MessageQueue(6436):   at android.os.MessageQueue.enqueueMessage(MessageQueue.java:196)
06-19 05:12:00.151: W/MessageQueue(6436):   at android.os.Handler.sendMessageAtTime(Handler.java:473)
06-19 05:12:00.151: W/MessageQueue(6436):   at android.os.Handler.sendMessageDelayed(Handler.java:446)
06-19 05:12:00.151: W/MessageQueue(6436):   at android.os.Handler.post(Handler.java:263)
06-19 05:12:00.151: W/MessageQueue(6436):   at android.os.ResultReceiver$MyResultReceiver.send(ResultReceiver.java:50)

我在这里看到类似的问题,但我感到很困惑(我没有使用任何AsyncTask,我已经找了CommonsWare代码wakefullIntent但我不理解它。)

这是NotificationsService.java的代码

public class NotificationsService extends IntentService {
private static  int TIME_INTERVAL_MILIS=90000;
private static final int REFRESH=10;
private  NotificationManager noteManager;
private static List<FlightStatusNote> flights= new ArrayList<FlightStatusNote>();



public NotificationsService(){
    super("NotificationsService");

}

@Override
public void onCreate(){
    Log.d("notificationsSservice","onCreate");
    super.onCreate();
    noteManager=(NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);
}



@Override
protected void onHandleIntent(Intent intent) {
    Log.d("NotificationsService","Me llamaron");

    Log.d("NotificationsService", "intervalo:"+NotificationsService.TIME_INTERVAL_MILIS);
        Log.d("NotificationsService","Itero por cada vuelo registrado para notificar");
        for(FlightStatusNote f: flights){
            FlightStatus fly=f.getFlight();
            Log.d("NotificationsService","Vuelo id:"+fly.getAirlineId()+fly.getNumberFlight());
            Intent intentaux=new Intent(Intent.ACTION_SYNC,null,getBaseContext(),FlightStatusService.class);
            intentaux.putExtra("airlineFlight", fly.getAirlineId());
            intentaux.putExtra("numberFlight",fly.getNumberFlight() );
            intentaux.putExtra("receiver", new ResultReceiver(new Handler()) {

                @Override
                protected void onReceiveResult(int resultCode, Bundle resultData) {
                    super.onReceiveResult(resultCode, resultData);
                    Log.d("notificationsService","response received");
                    if (resultCode == FlightStatusService.STATUS_OK) {
                        List<FlightStatus> fly =  (List<FlightStatus>)resultData.getSerializable("return");
                        for(FlightStatus f: fly){
                            int indexNote=flights.indexOf(new FlightStatusNote(f,null));
                            FlightStatusNote fsNote=flights.get(indexNote);
                            List<String> changes=fsNote.hasChanged(f);
                            if(changes==null){
                                Log.d("notificationsService","changes is null");
                            }
                            else{
                                Log.d("notficationsService", "comething changed");
                                createNotification(f, changes);
                            }

                        }


                    }

                }

            });
            startService(intentaux);
    }

        AlarmManager alarmMgr = (AlarmManager) getBaseContext().getSystemService(Context.ALARM_SERVICE);
          PendingIntent pendingIntent =  PendingIntent.getBroadcast(getBaseContext(), 0, new Intent(getBaseContext(), DealAlarmReceiver.class), 0);
          alarmMgr.set(AlarmManager.RTC, System.currentTimeMillis()+NotificationsService.TIME_INTERVAL_MILIS, pendingIntent);

}
}

如果有人可以帮助我,我会非常感激! 干杯!

编辑:我认为问题是收到的日志“响应”它没有出现。

5 个答案:

答案 0 :(得分:25)

IntentService在调用onHandleIntent方法时创建一个新线程,然后在onHandleIntent方法返回后立即终止该线程。

你需要在其他地方创建你的监听器,IntentService对于设置监听器是不安全的,因为它们会死掉。它们主要用于在主线程之外执行短任务。请参阅类似的问题here

修改:另请参阅IntentService上的文档。

答案 1 :(得分:5)

我无法回复因为我是新人,但基本上'jpalm'提到的是最准确的答案。

基本上有一件我理解与ServiceIntent一起玩的东西:他们会在他们完成后立刻死掉。这意味着如果你在框架中提交作品(比如开始一个Activity);框架可以立即回复给你,告诉你'startService(intentaux)'返回OK或者其他什么(我不是专家,我也是新手:P),因为它发现你的线程已经死了! !!。

当你开始你的活动时,如果你故意强迫你的线程活着,直到你得到响应,这种错误就不会发生。

http://developer.android.com/guide/components/services.html。将示例修改为不等待,然后Toast开始崩溃发送这样的清除消息,即使您认为自己没有使用ASYNC方法。

07-24 08:03:16.309: W/MessageQueue(1937): java.lang.RuntimeException: Handler (android.os.Handler) {b1016d80} sending message to a Handler on a dead thread
07-24 08:03:16.309: W/MessageQueue(1937):   at android.os.MessageQueue.enqueueMessage(MessageQueue.java:320)
07-24 08:03:16.309: W/MessageQueue(1937):   at android.os.Handler.enqueueMessage(Handler.java:626)
07-24 08:03:16.309: W/MessageQueue(1937):   at android.os.Handler.sendMessageAtTime(Handler.java:595)
07-24 08:03:16.309: W/MessageQueue(1937):   at android.os.Handler.sendMessageDelayed(Handler.java:566)
07-24 08:03:16.309: W/MessageQueue(1937):   at android.os.Handler.post(Handler.java:326)
07-24 08:03:16.309: W/MessageQueue(1937):   at android.widget.Toast$TN.hide(Toast.java:370)
07-24 08:03:16.309: W/MessageQueue(1937):   at android.app.ITransientNotification$Stub.onTransact(ITransientNotification.java:55)
07-24 08:03:16.309: W/MessageQueue(1937):   at android.os.Binder.execTransact(Binder.java:404)
07-24 08:03:16.309: W/MessageQueue(1937):   at dalvik.system.NativeStart.run(Native Method)

我不得不说android.developers的文档非常好但非常简洁(ULTRA ZIP),这意味着你必须逐字阅读和阅读,然后在绝望之后查看字典。 ..你说:它总是在这里! :o

它就像一本圣经,但对于开发者来说:)以某种方式我们成为Android的先知:P

答案 2 :(得分:5)

每个Handler都有LooperLooperHandlerThread。一般问题是当Handler与停止运行的线程关联时。如果有人试图使用Handler,它将失败并显示消息&#34;在死线程上向处理程序发送消息&#34;。

如果你只是做new Handler()它会与当前线程相关联(相反,它会与当前线程关联的Looper相关联)。如果你在一个即将消失的线程上执行此操作(例如IntentService的工作线程),你就会遇到这个问题。问题当然不仅限于这个根本原因,它可以以多种方式发生。

任何简单的解决方法都是构建您的Handler

Handler h = new Handler(Looper.getMainLooper());

这会将Handler与主循环器或永不消亡的主应用程序线程相关联。另一个更复杂的解决方法是为Handler创建一个专用线程,

HandlerThread ht = new HandlerThread(getClass().getName());
ht.start();
Handler handler = new Handler(ht.getLooper());

请注意,完成关联的quit()后,您需要明确HandlerThread Handler

答案 3 :(得分:0)

看这里

             intentaux.putExtra("receiver", new ResultReceiver(new Handler()) {

            @Override
            protected void onReceiveResult(int resultCode, Bundle resultData) {
                super.onReceiveResult(resultCode, resultData);
                Log.d("notificationsService","response received");
                if (resultCode == FlightStatusService.STATUS_OK) {
                    List<FlightStatus> fly =  (List<FlightStatus>)resultData.getSerializable("return");
                    for(FlightStatus f: fly){
                        int indexNote=flights.indexOf(new FlightStatusNote(f,null));
                        FlightStatusNote fsNote=flights.get(indexNote);
                        List<String> changes=fsNote.hasChanged(f);
                        if(changes==null){
                            Log.d("notificationsService","changes is null");
                        }
                        else{
                            Log.d("notficationsService", "comething changed");
                            createNotification(f, changes);
                        }

                    }


                }

            }

你发布一个annonimously定义的处理程序对象 - 为什么不将该处理程序对象绑定到一个活动(进程),然后查看代码是否中断?本质上,传入一个处理程序变量而不是一个新的处理程序对象。

这样,所有ResultReceivers都将使用相同的Handler对象而不是私有对象。

答案 4 :(得分:0)

主要原因是你把一条消息放在一个没有循环循环的队列上。 但是,你可以使用&#34; getMainLooper()&#34;作为参数传递给你创建的“处理程序”。

public AutoHandler(Context context, Looper looper) {
    super(looper);
    this.context = context;
}

你可以像这样创建一个AutoHandler实例:

autoHandler = new AutoHandler(this, getMainLooper());