android - studio - porque no puedo enviar mensajes de texto a un numero
Enviar mensaje a un manejador en un hilo muerto (5)
Cada Handler
tiene un Looper
y un Looper
tiene un HandlerThread
. El problema general es cuando un Handler
se asocia con un subproceso que deja de ejecutarse. Si alguien intenta usar el Handler
, fallará con el mensaje "enviar mensaje a un controlador en un hilo muerto".
Si solo haces un new Handler()
, se asocia con el hilo actual (más bien, se asocia con el Looper
asociado con el hilo actual). Si hace esto en un subproceso que desaparecerá (como el subproceso de trabajo para un IntentService
) tendrá el problema. Por supuesto, el problema no se limita a esta causa raíz, puede ocurrir de muchas maneras.
Cualquier solución fácil es construir tu Handler
como,
Handler h = new Handler(Looper.getMainLooper());
Esto asocia el Handler
con el looper principal, o el hilo principal de la aplicación que nunca morirá. Otra solución más compleja es crear un subproceso dedicado para el Handler
,
HandlerThread ht = new HandlerThread(getClass().getName());
ht.start();
Handler handler = new Handler(ht.getLooper());
Tenga en cuenta que necesita quit()
explícitamente quit()
HandlerThread
cuando haya terminado con el HandlerThread
asociado.
Estoy trabajando en un servicio en segundo plano que durante un período de tiempo encuesta a un servidor. El punto es que: tengo un IntentService (llamado NotificationsService) que llama a otro servicio, pero la respuesta de esta solicitud no vuelve. Y en el logcat aparece:
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)
Miré aquí problemas similares pero me confundí (no uso ninguna AsyncTask y busqué el código de CommonsWare wakefullIntent pero no lo entendí).
Aquí está el código para 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);
}
}
Si alguien me puede ayudar, lo apreciaría mucho! ¡Aclamaciones!
Edit: Creo que el problema es que la "respuesta recibida" del Log no aparece.
La razón principal es que ha puesto un mensaje en una cola que no tiene bucle. sin embargo, puede usar "getMainLooper ()" para pasar como parámetro al "Handler" que crea.
public AutoHandler(Context context, Looper looper) {
super(looper);
this.context = context;
}
y puedes crear una instancia de AutoHandler como esta:
autoHandler = new AutoHandler(this, getMainLooper());
No puedo responder porque soy nuevo, pero básicamente lo que se menciona ''jpalm'' es la respuesta más precisa.
Básicamente hay una cosa que entendí jugando con ServiceIntent: morirán en cuanto terminen. Lo que significa que si envía un trabajo en el marco (como comenzar una actividad); el Marco podría volver inmediatamente a ti para decirte que ''startService (intentux)'' regresó bien o lo que sea (no soy un experto, también soy nuevo en esto: P), ¡porque se encontró que tu hilo ya estaba muerto! !!.
Cuando comienzas tu actividad, si intencionalmente haces que tu hilo esté vivo de alguna manera hasta que obtengas la respuesta, estos errores no ocurren.
Consulte http://developer.android.com/guide/components/services.html . Modifique el ejemplo para que no espere, luego Toast comenzará a fallar y enviará mensajes claros como este, incluso cuando crea que no está utilizando el método 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)
Tengo que decir que la documentación de android.developers es bastante buena pero muy concisa (ULTRA ZIP), lo que significa que tendrá que leer y leer, palabra por palabra, y luego, cuando busque en un diccionario después de estar desesperado ... Di: ¡SIEMPRE ESTABA AQUÍ! : O
es como una Biblia, pero para los desarrolladores :) y de alguna manera nos estamos convirtiendo en profetas de Android: P
mira aquí
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);
}
}
}
}
publica un objeto de controlador definido de forma anónima; ¿por qué no vincular ese objeto de controlador a una actividad (proceso) y ver si el código se rompe entonces? Esencialmente, pasar una variable de controlador en lugar de un nuevo objeto de controlador.
de esa manera, todos los ResultReceivers usarán el mismo objeto Handler en lugar de uno privado.
IntentService
s crea un nuevo hilo cuando llama al método onHandleIntent
, y luego mata ese hilo tan pronto como regresa el método onHandleIntent
.
IntentService
crear su oyente en otro lugar, IntentService
no es seguro para configurar a los oyentes porque mueren. Se utilizan principalmente para ejecutar una tarea corta fuera del hilo principal. Vea una pregunta similar here .
Editar: También vea la documentación en IntentService .