Android 小部件从服务更新 - 内存泄漏?

发布于 2024-10-06 18:40:04 字数 3047 浏览 0 评论 0原文

我有一个 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

浮萍、无处依 2024-10-13 18:40:04

我有一个服务,我希望它每秒更新主屏幕上的一个小部件。

请不要那样做。应用程序小部件机制是为更新频率较低的内容而设计的 - 例如,每半小时一次。如果您这样做,您将把用户的电池打成糊状,并从他们的前台应用程序中窃取 CPU 时间(例如,降低他们正在玩的游戏的帧速率)。

一旦您将更新频率降低到合理的水平,请不要使用其唯一使命是跟踪时间的服务。请改用 AlarmManager

那么如何在不发生如此巨大的内存泄漏的情况下更新视图呢?

根据定义,如果它被垃圾收集,则不是泄漏。当您分配的内存被垃圾回收时,就会发生泄漏。因此,您没有泄漏内存。

哦我忘了:是的,我知道不建议每秒更新一次小部件,但我确实需要至少每 10 秒更新一次。

您的用户确实需要他们的设备具有可接受的性能。您的用户不需要您消耗所有这些 CPU 和 RAM。这意味着您的用户需要在市场上给您一星评级,因为您不考虑他们的需求,只考虑您的需求,就好像您更重要一样比他们是。

至少,使其可配置,以便用户实际上可以控制您的应用程序是否值得您所寻求的东西,而不是您向他们口述条款。

I have a Service and I want it to update a widget on the homescreen each second.

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.

So how can I update the view without having such a huge memory leaking?

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.

Oh I forgot: Yes, I know that updates of widgets each second are not recommended, but I really need a update at least every 10 seconds.

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文