Android NotificationListenerService lanza DeadObjectException
Tengo una implementación simple de NotificationListenerService
para probar la nueva API 4.3. El servicio mismo solía trabajar. Después de eso, agregué el envío de una emisión cuando se agrega una notificación de un paquete particular. Ahora, tan pronto como inicie el servicio, lanza una DeadObjectException
. Éste es el seguimiento de la pila:
E/NotificationService﹕ unable to notify listener (posted): android.service.notification.INotificationListener$Stub$Proxy@42c047a0 android.os.DeadObjectException at android.os.BinderProxy.transact(Native Method) at android.service.notification.INotificationListener$Stub$Proxy.onNotificationPosted(INotificationListener.java:102) at com.android.server.NotificationManagerService$NotificationListenerInfo.notifyPostedIfUserMatch(NotificationManagerService.java:241) at com.android.server.NotificationManagerService$2.run(NotificationManagerService.java:814) at android.os.Handler.handleCallback(Handler.java:730) at android.os.Handler.dispatchMessage(Handler.java:92) at android.os.Looper.loop(Looper.java:137) at com.android.server.ServerThread.run(SystemServer.java:1000)
Así es como inicie el servicio
- Captura de notificaciones de otras aplicaciones
- Preferencias compartidas entre dos procesos de la misma aplicación
- Uso de Job Scheduler en la API de Android <21
- Android: mantener vivo el servicio incluso el proceso padre es asesinado
- No se puede realizar la sincronización (onPerformSync no se llama)
@Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.action_start_service: startService(new Intent(this, ConnectService.class)); return true; default: return super.onOptionsItemSelected(item); } }
Puedo verificar que el servicio comienza, porque hago una onCreate()
en él es onCreate()
y onDestroy()
. Y aquí es cómo se maneja la publicación de notificaciones, si es necesario:
@Override public void onNotificationPosted(StatusBarNotification sbn) { Log.i(TAG, sbn.getNotification().toString()); if (sbn != null && sbn.getPackageName().equalsIgnoreCase(PKG)) { Intent intent = new Intent(ConnectService.NOTIFY); intent.putExtra("notification", sbn.getNotification().toString()); bManager.sendBroadcast(intent); } }
La cosa que chupa es que el rastro de la pila es inútil. ¿Qué sucede mal?
- ¿Cómo cancelar la tarea de repetición en el Administrador de alarmas?
- Android ResultReceiver a través de paquetes
- Android - Servicio de fondo de juego de Tamagotchi
- Notificación RemoteView en el oyente de clics
- ¿Cómo detener / cancelar el administrador de alarmas en otra actividad?
- Diferencias entre intención y pendiente
- El servicio de Android no se reinicia en lollipop
- No se pueden recibir las actualizaciones de ubicación de LocationClient después de que la pantalla se apagó
Trate de no iniciar el servicio usted mismo. Si ha habilitado NotificationListenerService
en la configuración de seguridad, el sistema debe enlazarla automáticamente.
Como alternativa, compruebe los registros de bloqueo para ver si su servicio se bloqueó o si su proceso se ha anulado. Creo que hay un error en el que si su NotificaitonListerService muere, el sistema no volverá a conectar hasta que reinicie el teléfono o cambie el permiso de notificaciones en la configuración de seguridad.
Me gustaría compartir mi respuesta debido a la información que recogí de diferentes temas en stackoverflow y mis propias pruebas. Si su NotificationListenerService falla (excepción, como IllegalStateException), el sistema lo eliminará y no lo restaurará de nuevo. Usted puede ver que en el logcat:
592-592/? E/NotificationService﹕ unable to notify listener (posted): android.service.notification.INotificationListener$Stub$Proxy@4291d008 android.os.DeadObjectException ....
Si el usuario va a Seguridad, Notificaciones, deshabilita y activa la aplicación, todavía no funciona. ¿Por qué? Porque sólo se reiniciará si el usuario reinicia el teléfono o si el usuario vuelve a habilitar la opción, pero ir a través de su aplicación mediante:
startActivity(new Intent("android.settings.ACTION_NOTIFICATION_LISTENER_SETTINGS"));
Así que tenemos que comprobar dos cosas, primero si la opción está habilitada:
private boolean checkNotificationSetting() { ContentResolver contentResolver = getContentResolver(); String enabledNotificationListeners = Settings.Secure.getString(contentResolver, "enabled_notification_listeners"); String packageName = getPackageName(); return !(enabledNotificationListeners == null || !enabledNotificationListeners.contains(packageName)); }
Si está habilitado, verificamos si el servicio es Muerte:
private boolean isNLServiceCrashed() { ActivityManager manager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE); List<ActivityManager.RunningServiceInfo> runningServiceInfos = manager.getRunningServices(Integer.MAX_VALUE); if (runningServiceInfos != null) { for (ActivityManager.RunningServiceInfo service : runningServiceInfos) { //NotificationListener.class is the name of my class (the one that has to extend from NotificationListenerService) if (NotificationListener.class.getName().equals(service.service.getClassName())) { if (service.crashCount > 0) { // in this situation we know that the notification listener service is not working for the app return true; } return false; } } } return false; }
¿Qué es este service.crashCount ? La documentación dice:
Número de veces que el proceso del servicio se ha estropeado mientras el servicio está funcionando.
Así que si su más de 0, significa que ya es la muerte. Por lo tanto, en ambos casos, tenemos que advertir al usuario y ofrecer la posibilidad de reiniciar el servicio con la intención que he publicado antes:
startActivity(new Intent("android.settings.ACTION_NOTIFICATION_LISTENER_SETTINGS"));
Por supuesto, si el servicio se bloquea, será bueno detectar por qué y cuándo prevenirlo también.