2010-12-10 27 views
2

J'ai un service qui appelle des méthodes de mise à jour dans un GameLogic -singleton. Le GameLogic peut décider qu'une mise à jour d'état est nécessaire. Dans ce cas, il informe ses auditeurs d'un StatusUpdateEvent. Les listeneres puis mettre à jour leur point de vue, etc.widget android après onDelete écoute encore

public class GameLogic { 
    // ... attributes ... 
    private static GameLogic instance = null; 
    private GameLogic() { 
     // singleton pattern 
    } 
    public static synchronized GameLogic getInstance() { 
     if (instance == null) { 
      instance = new GameLogic(); 
     } 
     return instance; 
    } 
    public void checkStatus() { 
     // called by service 
     // ... some checks 
     notifyStatusUpdate(new StatusUpdateEvent()); 
    } 
    public void addStatusUpdateListener(StatusUpdateListener listener) { 
     if (!listeners.contains(listener)) { 
      listeners.add(listener); 
     } 
    } 
    public void removeStatusUpdateListener(StatusUpdateListener listener) { 
     listeners.remove(listener); 
    } 
    protected synchronized void notifyStatusUpdate(StatusUpdateEvent event) { 
     for (StatusUpdateListener l : listeners) { 
      l.onStatusUpdate(event); 
     } 
    } 
} 

J'ai un widget qui devrait écouter la StatusUpdateEvent:

public class ProjectWidget extends AppWidgetProvider implements StatusUpdateListener { 
    // ... attributes ... 
    @Override 
    public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) { 
     this.context = context; 
     this.appWidgetManager = appWidgetManager; 
     this.remoteViews = new RemoteViews(context.getPackageName(), R.layout.widget_2x1); 
     this.thisWidget = new ComponentName(context, ProjectWidget.class); 

     GameLogic.getInstance().addStatusUpdateListener(this); 
    } 

    @Override 
    public void onDeleted(Context context, int[] appWidgetIds) { 
     Toast.makeText(context, "onDeleted", Toast.LENGTH_SHORT).show(); 
     GameLogic.getInstance().removeStatusUpdateListener(this); 
     super.onDeleted(context, appWidgetIds); 
    } 
    @Override 
    public void onStatusUpdate(StatusUpdateEvent e) { 
     android.util.Log.d("ProjectWidget", "onStatusUpdate"); 
     // here some class fields are updated like this.project = e.getProject(); 
     // ... 
     updateViews(); 
     appWidgetManager.updateAppWidget(thisWidget, remoteViews); 
    } 
    // ... updateViews() etc. 
} 

Mais le problème est maintenant: j'ajouter le widget à l'écran d'accueil, everythings bien . Ensuite, si je supprime le widget de l'écran d'accueil, je vois le toDelete Toast, mais après, je vois toujours cette entrée de journal: ProjectWidget onStatusUpdate.

Donc, l'écouteur n'est pas supprimé .. pourquoi? et comment puis-je faire ça?

Merci!

Répondre

3

Donc, l'écouteur n'est pas supprimé .. pourquoi? et comment puis-je faire ça?

Ce que vous avez est une fuite de mémoire. Le AppWidgetProvider est un objet transitoire.Il va vivre assez longtemps pour traiter une onUpdate() ou une autre méthode de cycle de vie de widget d'application, puis il s'en va.

Jamais jamais jamais jamais jamais jamais essayer d'avoir un AppWidgetProvider vivent plus longtemps que cela, comme en l'inscrivant dans un contexte statique que vous êtes. Vous perdez de la mémoire, car le AppWidgetProvider ne sera pas récupéré par les ordures.

Lorsque vous appelez removeStatusUpdateListener(), vous avez une instance AppWidgetProvider différente de celle utilisée avec addStatusUpdateListener(). Par conséquent, l'opération de suppression est un no-op (vous supprimez quelque chose jamais enregistré), et l'écouteur d'origine restera là pour toujours.

Avez-vous votre GameLogic ou quelque chose mettre à jour votre widget app RemoteViews directement.

+0

Merci, je n'étais pas au courant de la transience du AppWidgetProvider! Je le fais maintenant à partir du service: \t Context context = this; \t AppWidgetManager appWidgetManager = AppWidgetManager.getInstance (contexte); \t RemoteViews remoteViews = nouvelles RemoteViews (context.getPackageName(), R.layout.widget_2x1); \t ComponentName thisWidget = nouveau NomComposant (context, MyWidget.class); \t remoteViews.setTextViewText (R.id.my_text_view, "monTexte" + System.currentTimeMillis()); \t appWidgetManager.updateAppWidget (thisWidget, remoteViews); – Stuck

+0

@Stuck: Yup, c'est une bonne approche. 'AppWidgetProvider' n'est vraiment qu'un gestionnaire d'événements pour les événements de cycle de vie - vous pouvez mettre à jour le widget de l'application' RemoteViews' de n'importe où. – CommonsWare