29

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

}
}

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

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

4

5 回答 5

28

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

您需要在其他地方创建您的侦听器,IntentService因为它们会死,所以设置侦听器并不安全。它们主要用于在主线程之外执行一个短任务。在这里看到一个类似的问题。

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

于 2013-06-21T14:37:45.690 回答
10

每个Handler都有 a Looper,并且 aLooper与 a 相关联Thread(通常是 a HandlerThread)。一般问题是当 aHandler与停止运行的线程相关联时。如果有人尝试使用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());

请注意,当您完成关联quit()的.HandlerThreadHandler

于 2016-12-27T21:43:02.333 回答
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

于 2014-07-24T12:29:35.963 回答
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);
                        }

                    }


                }

            }

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

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

于 2013-06-21T14:37:30.030 回答
0

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

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

您可以像这样创建 AutoHandler 的实例:

autoHandler = new AutoHandler(this, getMainLooper());
于 2015-11-30T04:02:08.853 回答