android - putextra - intent-filter
IntentRecieverLeakedException, ¿Te estás perdiendo una llamada para anular el registro de Receiver()? en Android (7)
El error es muy explícito sobre tu problema. No está llamando a unregisterReceiver()
para el BroadcastReceiver
que registró con registerReceiver()
.
Estoy probando el siguiente ejemplo de SMS de: http://mobiforge.com/developing/story/sms-messaging-android pero recibo la siguiente excepción si intento enviar mensajes.
Exception:
02-07 12:38:15.447: ERROR/ActivityThread(839): Activity com.micro.MyTest has leaked IntentReceiver com.micro.MyTest$1@435a0c70
that was originally registered here. Are you missing a call to
unregisterReceiver()?
02-07 12:38:15.447: ERROR/ActivityThread(839): android.app.IntentReceiverLeaked: Activity com.test.SendSMS has leaked
IntentReceiver com.test.SendSMS $1@435a0c70 that was originally
registered here. Are you missing a call to unregisterReceiver()?
02-07 12:38:15.447: ERROR/ActivityThread(839): at android.app.ActivityThread$PackageInfo$ReceiverDispatcher.<init>(ActivityThread.java:707)
02-07 12:38:15.447: ERROR/ActivityThread(839): at android.app.ActivityThread$PackageInfo.getReceiverDispatcher(ActivityThread.java:535)
02-07 12:38:15.447: ERROR/ActivityThread(839): at android.app.ApplicationContext.registerReceiverInternal(ApplicationContext.java:748)
02-07 12:38:15.447: ERROR/ActivityThread(839): at android.app.ApplicationContext.registerReceiver(ApplicationContext.java:735)
02-07 12:38:15.447: ERROR/ActivityThread(839): at android.app.ApplicationContext.registerReceiver(ApplicationContext.java:729)
02-07 12:38:15.447: ERROR/ActivityThread(839): at android.content.ContextWrapper.registerReceiver(ContextWrapper.java:278)
02-07 12:38:15.447: ERROR/ActivityThread(839): at com.micro.MyTest.sendSMS(SendSMS .java:98)
02-07 12:38:15.447: ERROR/ActivityThread(839): at com.micro.MyTest.onCreate(SendSMS .java:42)
02-07 12:38:15.447: ERROR/ActivityThread(839): at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1123)
02-07 12:38:15.447: ERROR/ActivityThread(839): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2231)
02-07 12:38:15.447: ERROR/ActivityThread(839): at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2284)
02-07 12:38:15.447: ERROR/ActivityThread(839): at android.app.ActivityThread.access$1800(ActivityThread.java:112)
02-07 12:38:15.447: ERROR/ActivityThread(839): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1692)
02-07 12:38:15.447: ERROR/ActivityThread(839): at android.os.Handler.dispatchMessage(Handler.java:99)
02-07 12:38:15.447: ERROR/ActivityThread(839): at android.os.Looper.loop(Looper.java:123)
02-07 12:38:15.447: ERROR/ActivityThread(839): at android.app.ActivityThread.main(ActivityThread.java:3948)
02-07 12:38:15.447: ERROR/ActivityThread(839): at java.lang.reflect.Method.invokeNative(Native Method)
02-07 12:38:15.447: ERROR/ActivityThread(839): at java.lang.reflect.Method.invoke(Method.java:521)
02-07 12:38:15.447: ERROR/ActivityThread(839): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:782)
02-07 12:38:15.447: ERROR/ActivityThread(839): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:540)
02-07 12:38:15.447: ERROR/ActivityThread(839): at dalvik.system.NativeStart.main(Native Method)
02-07 12:38:15.496: ERROR/ActivityThread(839): Activity com.micro.MyTest has leaked IntentReceiver com.test.MyTest$2@435a13b8
that was originally registered here. Are you missing a call to
unregisterReceiver()?
02-07 12:38:15.496: ERROR/ActivityThread(839): android.app.IntentReceiverLeaked: Activity com.test.SendSMS has leaked
IntentReceiver com.test.SendSMS $2@435a13b8 that was originally
registered here. Are you missing a call to unregisterReceiver()?
02-07 12:38:15.496: ERROR/ActivityThread(839): at android.app.ActivityThread$PackageInfo$ReceiverDispatcher.<init>(ActivityThread.java:707)
02-07 12:38:15.496: ERROR/ActivityThread(839): at android.app.ActivityThread$PackageInfo.getReceiverDispatcher(ActivityThread.java:535)
02-07 12:38:15.496: ERROR/ActivityThread(839): at android.app.ApplicationContext.registerReceiverInternal(ApplicationContext.java:748)
02-07 12:38:15.496: ERROR/ActivityThread(839): at android.app.ApplicationContext.registerReceiver(ApplicationContext.java:735)
02-07 12:38:15.496: ERROR/ActivityThread(839): at android.app.ApplicationContext.registerReceiver(ApplicationContext.java:729)
02-07 12:38:15.496: ERROR/ActivityThread(839): at android.content.ContextWrapper.registerReceiver(ContextWrapper.java:278)
02-07 12:38:15.496: ERROR/ActivityThread(839): at com.micro.MyTest.sendSMS(SendSMS .java:129)
02-07 12:38:15.496: ERROR/ActivityThread(839): at com.micro.MyTest.onCreate(SendSMS .java:42)
02-07 12:38:15.496: ERROR/ActivityThread(839): at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1123)
02-07 12:38:15.496: ERROR/ActivityThread(839): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2231)
02-07 12:38:15.496: ERROR/ActivityThread(839): at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2284)
02-07 12:38:15.496: ERROR/ActivityThread(839): at android.app.ActivityThread.access$1800(ActivityThread.java:112)
02-07 12:38:15.496: ERROR/ActivityThread(839): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1692)
02-07 12:38:15.496: ERROR/ActivityThread(839): at android.os.Handler.dispatchMessage(Handler.java:99)
02-07 12:38:15.496: ERROR/ActivityThread(839): at android.os.Looper.loop(Looper.java:123)
02-07 12:38:15.496: ERROR/ActivityThread(839): at android.app.ActivityThread.main(ActivityThread.java:3948)
02-07 12:38:15.496: ERROR/ActivityThread(839): at java.lang.reflect.Method.invokeNative(Native Method)
02-07 12:38:15.496: ERROR/ActivityThread(839): at java.lang.reflect.Method.invoke(Method.java:521)
02-07 12:38:15.496: ERROR/ActivityThread(839): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:782)
02-07 12:38:15.496: ERROR/ActivityThread(839): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:540)
02-07 12:38:15.496: ERROR/ActivityThread(839): at dalvik.system.NativeStart.main(Native Method)
El método que envía sms
:
publicvoid sendSMS(String phoneNumber, String message) {
String SENT = "SMS_SENT";
String DELIVERED = "SMS_DELIVERED";
PendingIntent sentPI = PendingIntent.getBroadcast(this, 0, new Intent(SENT), 0);
PendingIntent deliveredPI = PendingIntent.getBroadcast(this, 0, new Intent(DELIVERED), 0);
// When the SMS has been sent, the following line (line 98) throws Exception
registerReceiver(
new BroadcastReceiver(){
public void onReceive(Context arg0, Intent arg1) {
switch (getResultCode()) {
case Activity.RESULT_OK:
Toast.makeText(getBaseContext(), "SMS Sent", Toast.LENGTH_SHORT).show();
break;
case SmsManager.RESULT_ERROR_GENERIC_FAILURE:
Toast.makeText(getBaseContext(), "Generic failure", Toast.LENGTH_SHORT).show();
break;
case SmsManager.RESULT_ERROR_NO_SERVICE:
Toast.makeText(getBaseContext(), "No service", Toast.LENGTH_SHORT).show();
break;
case SmsManager.RESULT_ERROR_NULL_PDU:
Toast.makeText(getBaseContext(), "Null PDU", Toast.LENGTH_SHORT).show();
break;
case SmsManager.RESULT_ERROR_RADIO_OFF:
Toast.makeText(getBaseContext(), "Radio off", Toast.LENGTH_SHORT).show();
break;
}
}
}, new IntentFilter(SENT));
// when the SMS has been delivered
registerReceiver(
new BroadcastReceiver() {
public void onReceive(Context arg0, Intent arg1) {
switch (getResultCode()) {
case Activity.RESULT_OK:
Toast.makeText(getBaseContext(), "SMS Delivered",Toast.LENGTH_SHORT).show();
break;
case Activity.RESULT_CANCELED:
Toast.makeText(getBaseContext(), "SMS not delivered", Toast.LENGTH_SHORT).show();
break;
}
}
},new IntentFilter(DELIVERED));
SmsManager sms = SmsManager.getDefault();
sms.sendTextMessage(phoneNumber, null, message, sentPI, deliveredPI);
}
Lo resolví con esto:
@Override
public void onReceive(Context arg0, Intent arg1) {
switch (getResultCode()) {
...
unregisterReceiver(this);
}
Lo último que debe hacer es cancelar el registro de difusión en onReceive
completo:
BroadcastReceiver smsReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context arg0, Intent arg1) {
switch (getResultCode()) {
case Activity.RESULT_OK:
if (Settings.registrarSucesso) {
...
}
break;
case SmsManager.RESULT_ERROR_GENERIC_FAILURE:
...
}
break;
case SmsManager.RESULT_ERROR_NO_SERVICE:
...
break;
case SmsManager.RESULT_ERROR_NULL_PDU:
...
break;
case SmsManager.RESULT_ERROR_RADIO_OFF:
...
break;
}
unregisterReceiver(this);
adapter.notifyDataSetChanged();
}
};
Use las siguientes dos clases para evitar este problema
import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
public class SmsDeliveredReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent arg1) {
switch (getResultCode()) {
case Activity.RESULT_OK:
Log.d("httpmon", "SMS delivered");
break;
case Activity.RESULT_CANCELED:
Log.d("httpmon", "SMS not delivered");
break;
}
}
}
y este para el receptor enviado SMS
import java.util.Collections;
import java.util.HashMap;
import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.PowerManager;
import android.os.PowerManager.WakeLock;
import android.telephony.gsm.SmsManager;
import android.util.Log;
public class SmsSentReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent arg1) {
switch (getResultCode()) {
case Activity.RESULT_OK:
Log.d("httpmon", "SMS sent");
break;
case SmsManager.RESULT_ERROR_GENERIC_FAILURE:
Log.d("httpmon", "SMS generic failure");
break;
case SmsManager.RESULT_ERROR_NO_SERVICE:
Log.d("httpmon", "SMS no service");
break;
case SmsManager.RESULT_ERROR_NULL_PDU:
Log.d("httpmon", "SMS null PDU");
break;
case SmsManager.RESULT_ERROR_RADIO_OFF:
Log.d("httpmon", "SMS radio off");
break;
}
}
}
y finalmente configura el receptor en tu archivo de manifiesto
<receiver android:name=".SmsSentReceiver">
<intent-filter>
<action android:name="SMS_SENT" />
</intent-filter>
</receiver>
<receiver android:name=".SmsDeliveredReceiver">
<intent-filter>
<action android:name="SMS_DELIVERED" />
</intent-filter>
</receiver>
en su clase de actividad, declare estas variables globales:
private BroadcastReceiver sendBroadcastReceiver;
private BroadcastReceiver deliveryBroadcastReceiver;
String SENT = "SMS_SENT";
String DELIVERED = "SMS_DELIVERED";
anular la creación de su actividad y registrar sus receptores:
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
sendBroadcastReceiver = new BroadcastReceiver()
{
public void onReceive(Context arg0, Intent arg1)
{
switch (getResultCode())
{
case Activity.RESULT_OK:
Toast.makeText(getBaseContext(), "SMS Sent", Toast.LENGTH_SHORT).show();
break;
case SmsManager.RESULT_ERROR_GENERIC_FAILURE:
Toast.makeText(getBaseContext(), "Generic failure", Toast.LENGTH_SHORT).show();
break;
case SmsManager.RESULT_ERROR_NO_SERVICE:
Toast.makeText(getBaseContext(), "No service", Toast.LENGTH_SHORT).show();
break;
case SmsManager.RESULT_ERROR_NULL_PDU:
Toast.makeText(getBaseContext(), "Null PDU", Toast.LENGTH_SHORT).show();
break;
case SmsManager.RESULT_ERROR_RADIO_OFF:
Toast.makeText(getBaseContext(), "Radio off", Toast.LENGTH_SHORT).show();
break;
}
}
};
deliveryBroadcastReceiver = new BroadcastReceiver()
{
public void onReceive(Context arg0, Intent arg1)
{
switch (getResultCode())
{
case Activity.RESULT_OK:
Toast.makeText(getBaseContext(), "SMS Delivered", Toast.LENGTH_SHORT).show();
break;
case Activity.RESULT_CANCELED:
Toast.makeText(getBaseContext(), "SMS not delivered", Toast.LENGTH_SHORT).show();
break;
}
}
};
registerReceiver(deliveryBroadcastReceiver, new IntentFilter(DELIVERED));
registerReceiver(sendBroadcastReceiver , new IntentFilter(SENT));
}
a continuación, su método de envío de sms queda con solo 6 líneas de código:
public void sendSMS(String phoneNumber, String message)
{
String SENT = "SMS_SENT";
String DELIVERED = "SMS_DELIVERED";
PendingIntent sentPI = PendingIntent.getBroadcast(this, 0, new Intent(SENT), 0);
PendingIntent deliveredPI = PendingIntent.getBroadcast(this, 0, new Intent(DELIVERED), 0);
SmsManager sms = SmsManager.getDefault();
sms.sendTextMessage(phoneNumber, null, message, sentPI, deliveredPI);
}
por último, anule el registro de sus receptores al finalizar su actividad:
@Override
protected void onStop()
{
unregisterReceiver(sendBroadcastReceiver);
unregisterReceiver(deliveryBroadcastReceiver);
super.onStop();
}
mientras se registra:
rec = new BroadcastReceiver()
{
....
}
para evitar fugas del receptor:
onStop()
{
super.onStop();
unregisterReciever(rec);
}
tratar
private void sendSMS()
{
String SENT = "SMS_SENT";
String DELIVERED = "SMS_DELIVERED";
PendingIntent sentPI = PendingIntent.getBroadcast(this, 0, new Intent(SENT), 0);
PendingIntent deliveredPI = PendingIntent.getBroadcast(this, 0, new Intent(DELIVERED), 0);
SmsManager sms = SmsManager.getDefault();
sms.sendTextMessage(phoneNumber, null, message, sentPI, deliveredPI);
sendBroadcastReceiver = new BroadcastReceiver()
{
public void onReceive(Context arg0, Intent arg1)
{
switch (getResultCode())
{
case Activity.RESULT_OK:
Toast.makeText(getBaseContext(), "SMS Sent", Toast.LENGTH_SHORT).show();
break;
case SmsManager.RESULT_ERROR_GENERIC_FAILURE:
Toast.makeText(getBaseContext(), "Generic failure", Toast.LENGTH_SHORT).show();
break;
case SmsManager.RESULT_ERROR_NO_SERVICE:
Toast.makeText(getBaseContext(), "No service", Toast.LENGTH_SHORT).show();
break;
case SmsManager.RESULT_ERROR_NULL_PDU:
Toast.makeText(getBaseContext(), "Null PDU", Toast.LENGTH_SHORT).show();
break;
case SmsManager.RESULT_ERROR_RADIO_OFF:
Toast.makeText(getBaseContext(), "Radio off", Toast.LENGTH_SHORT).show();
break;
}
unregisterReceiver(sendBroadcastReceiver);//add here
}
};
deliveryBroadcastReceiver = new BroadcastReceiver()
{
public void onReceive(Context arg0, Intent arg1)
{
switch (getResultCode())
{
case Activity.RESULT_OK:
Toast.makeText(getBaseContext(), "SMS Delivered", Toast.LENGTH_SHORT).show();
break;
case Activity.RESULT_CANCELED:
Toast.makeText(getBaseContext(), "SMS not delivered", Toast.LENGTH_SHORT).show();
break;
}
unregisterReceiver(deliveryBroadcastReceiver);//add here
}
};
registerReceiver(deliveryBroadcastReceiver, new IntentFilter(DELIVERED));
registerReceiver(sendBroadcastReceiver , new IntentFilter(SENT));
}
onCreate & onStop
no siempre son los mejores lugares para register & unregister
onCreate & onStop
register & unregister
cuando se mantiene el historial de actividad. Debe colocar registerReceiver & unregisterReceiver
en onResume & onPause
.
@Override
protected void onResume() {
registerReceiver(deliveryBroadcastReceiver, new IntentFilter(DELIVERED));
registerReceiver(sendBroadcastReceiver , new IntentFilter(SENT));
super.onResume();
}
@Override
protected void onPause() {
try {
unregisterReceiver(sendBroadcastReceiver);
unregisterReceiver(deliveryBroadcastReceiver);
} catch (IllegalArgumentException ex) {
// If Receiver not registered
}
super.onPause();
}