【问题标题】:sending message to a handler on a dead thread在死线程上向处理程序发送消息
【发布时间】:2013-06-18 17:35:12
【问题描述】:

我正在开发一项后台服务,该服务会在一段时间内轮询服务器某事。关键是:我有一个调用另一个服务的 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);

}
}

如果有人可以帮助我,我将不胜感激! 干杯!

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

【问题讨论】:

    标签: android


    【解决方案1】:

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

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

    编辑:另请参阅IntentService 上的文档。

    【讨论】:

    • 我已经读过类似的问题,但我仍然卡住了。我还应该在哪里创建监听器?
    • 我建议使用“onStartCommand”,它会传递您发送到“onHandleIntent”的所有意图。
    【解决方案2】:

    每个Handler 都有一个Looper,一个Looper 有一个HandlerThread。一般问题是当Handler 与停止运行的线程相关联时。如果有人尝试使用Handler,它将失败并显示消息“向死线程上的处理程序发送消息”。

    如果您只是执行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());
    

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

    【讨论】:

    • 使用来自服务的 Messenger 获取“此消息已在使用中”和死对象异常
    【解决方案3】:

    我是新手,无法回复,但基本上'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

    【讨论】:

      【解决方案4】:

      看这里

                   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);
                              }
      
                          }
      
      
                      }
      
                  }
      

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

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

      【讨论】:

        【解决方案5】:

        主要原因是您将消息放在没有循环器循环的队列中。 但是,您可以使用“getMainLooper()”作为参数传递给您创建的“处理程序”。

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

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

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

        【讨论】:

          猜你喜欢
          • 2013-12-02
          • 2019-08-30
          • 1970-01-01
          • 2016-10-05
          • 1970-01-01
          • 1970-01-01
          • 2023-04-02
          • 2011-04-08
          • 1970-01-01
          相关资源
          最近更新 更多