I have a Service that calls some update-methods in a GameLogic
-singleton. TheGameLogic
may decide that some status-update is needed. In this case it informs its listeners about a StatusUpdateEvent
. The listeneres then update their view etc.
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);
}
}
}
I have a widget that should listen to the 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);
}
@Overri开发者_如何学编程de
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.
}
But the problem now is: I add the widget to the homescreen, everythings fine. Then if I delete the widget from the homescreen, I see the onDelete Toast, but afterwards I still see that Log entry: ProjectWidget onStatusUpdate.
So the listener is not removed.. why? and how can I do that stuff?
Thanks!
So the listener is not removed.. why? and how can I do that stuff?
What you have is a memory leak.
The AppWidgetProvider
is a transient object. It will live long enough to process an onUpdate()
or other app widget lifecycle method, and then it goes away.
Never never never never never never try to have an AppWidgetProvider
live longer than this, such as by registering it in a static context as you are. You are leaking memory, as the AppWidgetProvider
will not get garbage-collected.
When you are calling removeStatusUpdateListener()
, you have a different AppWidgetProvider
instance than you used with addStatusUpdateListener()
. Hence, the remove operation is a no-op (you are removing something never registered), and the original listener will remain there forever.
Have your GameLogic
or whatever update your app widget RemoteViews
directly.
精彩评论