Android 小部件从服务更新 - 内存泄漏?
我有一个 Service
,我希望它每秒更新主屏幕上的一个小部件。因此,服务每秒侦听由 TimeController
发送的 OnTimerEvent。 TimeController
是一个单例,持有一个运行 mUpdateTimeTask
的处理程序:
public class TimeController {
private long startTime = -1;
// ... attributes ... listeners etc
private Runnable mUpdateTimeTask = new Runnable() {
public void run() {
TimeController.this.notify(new TimerUpdateEvent(this));
startTime += DateUtils.SECOND_IN_MILLIS;
mHandler.postAtTime(this, startTime);
}
};
public void startTimer() {
// if not already running
if (startTime == -1) {
startTime = SystemClock.uptimeMillis();
mHandler.removeCallbacks(mUpdateTimeTask);
mHandler.postDelayed(mUpdateTimeTask, 0);
}
};
// ...
}
这一切都有效,并且小部件已更新,但在 Logcat 中我看到:
12-10 22:06:42.825: DEBUG/dalvikvm(1738): GC freed 17488 objects / 651080 bytes in 112ms
12-10 22:06:44.035: DEBUG/dalvikvm(1738): GC freed 17479 objects / 650832 bytes in 172ms
12-10 22:06:45.205: DEBUG/dalvikvm(1738): GC freed 17428 objects / 649744 bytes in 97ms
12-10 22:06:46.315: DEBUG/dalvikvm(1738): GC freed 17463 objects / 650656 bytes in 86ms
12-10 22:06:47.725: DEBUG/dalvikvm(1738): GC freed 17793 objects / 663872 bytes in 85ms
12-10 22:06:48.985: DEBUG/dalvikvm(1738): GC freed 17026 objects / 633944 bytes in 176ms
12-10 22:06:50.145: DEBUG/dalvikvm(1738): GC freed 17492 objects / 651352 bytes in 89ms
12-10 22:06:51.674: DEBUG/dalvikvm(1738): GC freed 17435 objects / 650320 bytes in 105ms
12-10 22:06:52.934: DEBUG/dalvikvm(1738): GC freed 17519 objects / 652584 bytes in 109ms
12-10 22:06:54.234: DEBUG/dalvikvm(1738): GC freed 17487 objects / 650920 bytes in 90ms
12-10 22:06:55.645: DEBUG/dalvikvm(1738): GC freed 17685 objects / 659448 bytes in 91ms
而且我不喜欢我所看到的... :-)
public class MyService extends Service implements TimerUpdateListener {
@Override
public void onCreate() {
timeController = TimeController.getInstance();
timeController.addListener(this);
timeController.startTimer();
appWidgetManager = AppWidgetManager.getInstance(this);
remoteViews = new RemoteViews(this.getPackageName(), R.layout.widget_2x1);
projectWidget = new ComponentName(this, ProjectWidget.class);
super.onCreate();
}
@Override
public void onTimerUpdate(TimerUpdateEvent e) {
updateWidgetViews();
}
private void updateWidgetViews() {
// only update widgets if some exist
if (appWidgetManager.getAppWidgetIds(projectWidget).length > 0) {
remoteViews.setTextViewText(R.id.time, MyDateUtils.timeLeftAsString(project.getInCurrentLevelSince()));
appWidgetManager.updateAppWidget(projectWidget, remoteViews);
}
}
}
如果我注释掉 remoteViews.setTextViewText(...)
GC 消息不会出现。那么如何在不产生如此大的内存泄漏的情况下更新视图呢?
谢谢!
I have a Service
and I want it to update a widget on the homescreen each second. Therfore the Service listenes to an OnTimerEvent which is send by an TimeController
each second. The TimeController
is a singleton holding a handler which runs mUpdateTimeTask
:
public class TimeController {
private long startTime = -1;
// ... attributes ... listeners etc
private Runnable mUpdateTimeTask = new Runnable() {
public void run() {
TimeController.this.notify(new TimerUpdateEvent(this));
startTime += DateUtils.SECOND_IN_MILLIS;
mHandler.postAtTime(this, startTime);
}
};
public void startTimer() {
// if not already running
if (startTime == -1) {
startTime = SystemClock.uptimeMillis();
mHandler.removeCallbacks(mUpdateTimeTask);
mHandler.postDelayed(mUpdateTimeTask, 0);
}
};
// ...
}
This all works and the widget get's updated, but in Logcat I see:
12-10 22:06:42.825: DEBUG/dalvikvm(1738): GC freed 17488 objects / 651080 bytes in 112ms
12-10 22:06:44.035: DEBUG/dalvikvm(1738): GC freed 17479 objects / 650832 bytes in 172ms
12-10 22:06:45.205: DEBUG/dalvikvm(1738): GC freed 17428 objects / 649744 bytes in 97ms
12-10 22:06:46.315: DEBUG/dalvikvm(1738): GC freed 17463 objects / 650656 bytes in 86ms
12-10 22:06:47.725: DEBUG/dalvikvm(1738): GC freed 17793 objects / 663872 bytes in 85ms
12-10 22:06:48.985: DEBUG/dalvikvm(1738): GC freed 17026 objects / 633944 bytes in 176ms
12-10 22:06:50.145: DEBUG/dalvikvm(1738): GC freed 17492 objects / 651352 bytes in 89ms
12-10 22:06:51.674: DEBUG/dalvikvm(1738): GC freed 17435 objects / 650320 bytes in 105ms
12-10 22:06:52.934: DEBUG/dalvikvm(1738): GC freed 17519 objects / 652584 bytes in 109ms
12-10 22:06:54.234: DEBUG/dalvikvm(1738): GC freed 17487 objects / 650920 bytes in 90ms
12-10 22:06:55.645: DEBUG/dalvikvm(1738): GC freed 17685 objects / 659448 bytes in 91ms
And I don't like what I see... :-)
public class MyService extends Service implements TimerUpdateListener {
@Override
public void onCreate() {
timeController = TimeController.getInstance();
timeController.addListener(this);
timeController.startTimer();
appWidgetManager = AppWidgetManager.getInstance(this);
remoteViews = new RemoteViews(this.getPackageName(), R.layout.widget_2x1);
projectWidget = new ComponentName(this, ProjectWidget.class);
super.onCreate();
}
@Override
public void onTimerUpdate(TimerUpdateEvent e) {
updateWidgetViews();
}
private void updateWidgetViews() {
// only update widgets if some exist
if (appWidgetManager.getAppWidgetIds(projectWidget).length > 0) {
remoteViews.setTextViewText(R.id.time, MyDateUtils.timeLeftAsString(project.getInCurrentLevelSince()));
appWidgetManager.updateAppWidget(projectWidget, remoteViews);
}
}
}
If I comment out the remoteViews.setTextViewText(...)
the GC messages do not appear. So how can I update the view without having such a huge memory leaking?
Thanks!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
请不要那样做。应用程序小部件机制是为更新频率较低的内容而设计的 - 例如,每半小时一次。如果您这样做,您将把用户的电池打成糊状,并从他们的前台应用程序中窃取 CPU 时间(例如,降低他们正在玩的游戏的帧速率)。
一旦您将更新频率降低到合理的水平,请不要使用其唯一使命是跟踪时间的服务。请改用
AlarmManager
。根据定义,如果它被垃圾收集,则不是泄漏。当您分配的内存未被垃圾回收时,就会发生泄漏。因此,您没有泄漏内存。
您的用户确实需要他们的设备具有可接受的性能。您的用户不需要您消耗所有这些 CPU 和 RAM。这意味着您的用户需要在市场上给您一星评级,因为您不考虑他们的需求,只考虑您的需求,就好像您更重要一样比他们是。
至少,使其可配置,以便用户实际上可以控制您的应用程序是否值得您所寻求的东西,而不是您向他们口述条款。
Please do not do that. The app widget mechanism is designed for stuff that is updated much less frequently -- say, once every half-hour. You will hammer the user's battery into paste if you do this, and steal CPU time from their foreground app (e.g., cutting frame rate of the game they are playing).
Once you drop the update frequency to something reasonable, please do not have a service whose sole mission in life is to track time. Use
AlarmManager
instead.By definition, if it is being garbage-collected, it is not a leak. A leak occurs when you allocate memory that is not garbage-collected. Hence, you are not leaking memory.
Your users really need acceptable performance out of their devices. Your users do not need you consuming all this CPU and RAM. Which means your users need to give you one-star ratings on the Market for being inconsiderate of what they need, thinking only of what you need, as if you are more important than they are.
At minimum, make this be configurable, so the user actually gets to control whether or not your app deserves what you seek, rather than you dictating terms to them.