Pushwoosh filtrando mi actividad

Estoy utilizando Pushwoosh dentro de mi aplicación para recibir notificaciones push. Estoy utilizando la última versión de la biblioteca Pushwoosh 3.1.14.

Tengo una estructura de pantalla como esta.

Login Activity -> Main Activity with multiple tabs. 

Así que estoy implementando mi lógica pushwoosh relacionada dentro de MainActivity. Y quiero anular el registro de push on Logout, y volver a la actividad de inicio de sesión.

Mi código se da a continuación. He filtrado todas las otras secciones no relacionadas con Pushwoosh. Para ser franco, este código es exactamente similar al código en la documentación Pushwoosh aquí . La única diferencia es en el método onLogout () donde intento anular el registro de pushwoosh y volver a LoginActivity.

TabbarActivity.java

 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); //Pushwoosh Registration registerReceivers(); PushManager pushManager = PushManager.getInstance(this); pushManager.setNotificationFactory(new PushNotificationFactory()); try { pushManager.onStartup(this); } catch(Exception e) {} //Register for push! pushManager.registerForPushNotifications(); checkMessage(getIntent()); } @Override protected void onNewIntent(Intent intent) { super.onNewIntent(intent); setIntent(intent); checkMessage(intent); } @Override protected void onResume() { super.onResume(); registerReceivers(); } @Override protected void onPause() { super.onPause(); unregisterReceivers(); } BroadcastReceiver mBroadcastReceiver = new BaseRegistrationReceiver() { @Override public void onRegisterActionReceive(Context context, Intent intent) { checkMessage(intent); } }; private BroadcastReceiver mReceiver = new BasePushMessageReceiver() { @Override protected void onMessageReceive(Intent intent) { //JSON_DATA_KEY contains JSON payload of push notification. } }; public void registerReceivers() { IntentFilter intentFilter = new IntentFilter( getPackageName() + ".action.PUSH_MESSAGE_RECEIVE"); registerReceiver(mReceiver, intentFilter, getPackageName() +".permission.C2D_MESSAGE", null); registerReceiver(mBroadcastReceiver, new IntentFilter( getPackageName() + "." + PushManager.REGISTER_BROAD_CAST_ACTION)); } public void unregisterReceivers() { try { unregisterReceiver(mReceiver); } catch (Exception e) { e.printStackTrace(); } try { unregisterReceiver(mBroadcastReceiver); } catch (Exception e) { e.printStackTrace(); } } private void checkMessage(Intent intent) { if (null != intent) { if (intent.hasExtra(PushManager.REGISTER_EVENT)) { uploadPushTokenToServer(PushManager.getPushToken(this)); } resetIntentValues(); } } private void resetIntentValues() { Intent mainAppIntent = getIntent(); if (mainAppIntent.hasExtra(PushManager.PUSH_RECEIVE_EVENT)) { mainAppIntent.removeExtra(PushManager.PUSH_RECEIVE_EVENT); } else if (mainAppIntent.hasExtra(PushManager.REGISTER_EVENT)) { mainAppIntent.removeExtra(PushManager.REGISTER_EVENT); } else if (mainAppIntent.hasExtra(PushManager.UNREGISTER_EVENT)) { mainAppIntent.removeExtra(PushManager.UNREGISTER_EVENT); } else if (mainAppIntent.hasExtra(PushManager.REGISTER_ERROR_EVENT)) { mainAppIntent.removeExtra(PushManager.REGISTER_ERROR_EVENT); } else if (mainAppIntent.hasExtra(PushManager.UNREGISTER_ERROR_EVENT)) { mainAppIntent.removeExtra(PushManager.UNREGISTER_ERROR_EVENT); } setIntent(mainAppIntent); } //Finally on logout private void onLogout() { //other cleanup //pushwoosh PushManager.getInstance(this).unregisterForPushNotifications(); //goback to login activity } 

Estoy recibiendo empujes del servidor sin ningún problema. El único problema al que me enfrento es después de cerrar la sesión y volver a LoginActivity, TabbarActivity permanece en la memoria, que a su vez se aferran a muchos otros fragmentos y vistas. He intentado depurar usando MAT y esto es lo que aparece.

 Class Name | Ref. Objects | Shallow Heap | Ref. Shallow Heap | Retained Heap -------------------------------------------------------------------------------------------------------------------------------------------------- com.pushwoosh.internal.request.RequestManager$1 @ 0x12f89ce0 Thread-1737 Thread| 1 | 88 | 360 | 536 '- val$context in.myproject.activities.TabbarActivity @ 0x12d8ac40 | 1 | 360 | 360 | 18,520 -------------------------------------------------------------------------------------------------------------------------------------------------- 

También he comprobado el mismo con la herramienta LeakCanary, que también indica que Pushwoosh se aferra a mi actividad.

Así que mi pregunta es, ¿cómo puedo limpiar pushwoosh para evitar que mi actividad se filtró?

Los documentos a los que has hecho referencia, al mirarlos brevemente, están dando un ejemplo y estos ejemplos no siempre son la mejor manera de implementar la api en una aplicación completamente funcional con otras actividades. Entiendo usando getInstance, usted está intentando utilizar un singleton, pero sospecho que esto no está siendo manejado bien.

Tomaría el control de la instancia de PushManager que se está utilizando para la duración de su aplicación.

El problema puede ser la instancia múltiple de PushManager que se crea tanto desde el ámbito y la creación de múltiples instancias de pushManager dentro de la clase, y posiblemente dentro de la vida del programa. Esto causará fugas.

Estaría haciendo pushManager una variable de clase, en lugar de usar PushManager.getInstance dos veces y considerar la creación de una instancia estática de la PushManager para ser utilizado durante la duración de la aplicación, al igual que el uso de una sola instancia de base de datos en toda una aplicación.

A nivel de clase:

 PushManager pushManager; 

Y la inicialización en el

 pushManager = PushManager.getInstance(this); //Finally on logout private void onLogout() { //other cleanup //pushwoosh // Here the first instance is left dangling. // PushManager.getInstance(this).unregisterForPushNotifications(); pushManager..unregisterForPushNotifications(); //goback to login activity } 

De esta manera, habrá limpiado los recursos de la instancia de pushmanager.

Para utilizar un PushManager estático de amplia aplicación:

 static PushManager pushManager; 

Inicializado como:

 pushManager = new PushManager(this.getApplicationContext()); 

¿Cuándo es un Singleton no un Singleton?

El comentario de @ CommonsWare es perfecto. Mirando el código fuente (descompilado) del Pushwoosh SDK, PushManager.onStartUp() reenvía el contexto suministrado directamente a su RequestManager , que a su vez lo entrega a un Thread que básicamente sigue funcionando infinitamente. Lo que significa que se bloqueará en su instancia de actividad mucho después de que se ha convertido en no válido.

Tenga en cuenta que esto es exactamente lo que MAT está tratando de decirle (y LeakCanary demasiado probablemente).

En otras palabras, internamente se hará una referencia fuerte a todo lo que pase en onStartUp() , durante toda la vida de su aplicación. Como tal, asegúrese de que el contexto que usted proporciona tiene un ciclo de vida con un alcance adecuado. En otras palabras: la única opción correcta aquí es el contexto de la aplicación.

Es posible que desee presentar un informe de error con Pushwoosh e informarles que el problema es:

 public void onStartup(Context context) throws Exception { Context applicationContext = context.getApplicationContext(); this.pushRegistrar.checkDevice(applicationContext); sendAppOpen(context); // <--- ISSUE ... } 

Sólo puedo imaginar que alguien tuvo un mal día en la oficina y se olvidó de cambiar la línea problemática en sendAppOpen(applicationContext) .

Ninguna promesa de que todas las fugas serán historia después de este cambio (no hundí demasiado en la fuente), pero debería por lo menos resolver el problema inmediato en cuestión.

Además, y esto no se puede enfatizar lo suficiente, en general, si no sabes (o controlas) el tiempo de vida de un componente, usa el contexto de la aplicación. Si realmente se necesita una actividad, la firma del método lo indicará. Si sólo está pidiendo un contexto, hágalo seguro. (Y sí, por supuesto hay un montón de excepciones a esta regla general, pero generalmente es más fácil rastrear que los problemas de abajo como resultado de que en lugar de los de fugas de memoria).

Bueno, tengo una respuesta de Pushwoosh diciendo que han arreglado el problema. He descargado su último SDK y voila, la fuga había desaparecido. Y parece que el usuario @MH estaba al tanto del código culpable.

Esto es de código fuente descompilado de nuevo SDK,

 public void onStartup(Context context) throws Exception { Context applicationContext = context.getApplicationContext(); this.pushRegistrar.checkDevice(applicationContext); sendAppOpen(applicationContext); // <--- NO ISSUE ... } 
  • Herramientas de análisis de memoria / rendimiento para Android
  • Necesita ayuda para comprender la pérdida de memoria en mi aplicación de Android
  • API básica de Android v2 MapActivity outOfMemory con 10 marcadores
  • Android: ¿Cuánta memoria utiliza mi aplicación?
  • Cómo implementar el almacenamiento en caché ListView en Android
  • Problema de memoria de Viewview de Viewpager
  • Android: libera recursos de memoria de mapa de bits de forma programática
  • Atascado en "Vaciar memoria, la aplicación se congelará. Brrr. "Mensaje
  • Reciclaje de bitmaps
  • Android procesamiento de imágenes de alta resolución
  • Android sin memoria al asignar variables
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.