2010-12-10 3 views
1

У меня есть Service, и я хочу, чтобы он обновлял виджет на главном экране каждую секунду. Поэтому служба прослушивает OnTimerEvent, который отправляется TimeController каждую секунду. TimeController одноэлементно держит обработчик, который работает mUpdateTimeTask:Обновление виджета Android от службы - утечка памяти?

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(...) ГЦ сообщения не отображаются. Итак, как я могу обновить представление без утечки огромной памяти?

Спасибо!

+0

О, я забыл: Да, я знаю, что обновление виджета каждую секунду не рекомендуется, но мне действительно нужно обновление не реже одного раза в 10 секунд. В любом случае, я задаюсь вопросом, является ли этот GC утечкой памяти или если это вызвано часто обновлениями? – Stuck

+0

Я предполагаю, что что-то выделяется в MyDateUtils.timeLeftAsString(); - Могли бы вы опубликовать эту функцию? – danh32

+0

@ danh32, если я прокомментирую это и поставлю туда фиксированную строку, произойдет такое же распределение. – Stuck

ответ

4

У меня есть служба, и я хочу, чтобы она обновляла виджет на главном экране каждую секунду.

Пожалуйста, не делайте этого. Механизм виджета приложений предназначен для материалов, которые обновляются гораздо реже - скажем, каждые полчаса. Если вы сделаете это, вы забиваете батарею пользователя, и крадете процессорное время из своего приложения переднего плана (например, сократите частоту кадров в игре, которую они играют).

Как только вы снижаете частоту обновления до чего-то разумного, пожалуйста, не имеете услуги, единственной миссией в жизни является отслеживание времени. Вместо этого используйте AlarmManager.

Так как я могу обновить представление без утечки огромной памяти?

По определению, если это сбор мусора, это не утечка. Утечка возникает, когда вы выделяете память не сбор мусора. Следовательно, вы не теряете память.

О, я забыл: Да, я знаю, что обновление виджета каждую секунду не рекомендуется, но мне действительно нужно обновление не реже одного раза в 10 секунд.

Ваши пользователи действительно нуждаются в приемлемой производительности из своих устройств. Ваши пользователи не нуждаются в вас, потребляя весь этот процессор и оперативную память. Это означает, что ваши пользователи должны дать вам однозвездочные рейтинги на рынке за то, что они не учитывают то, что они нужны, думая только о том, что вам нужно, как если бы вы были важнее, чем они есть.

Как минимум, сделайте это возможным, чтобы пользователь мог контролировать, заслуживает ли ваше приложение то, что вы ищете, а не диктуете им условия.

+1

Спасибо. Хорошо было бы хорошо, если бы виджет действительно отсчитывал количество секунд ... но нормально .. Таймер всегда отсчитывает неделю, поэтому я сделаю это так: обновляйте каждый час, пока не останется меньше 2 часов. Затем я буду обновлять каждые 10 минут. В последний час или последние 30 минут я буду делать обновление каждую минуту, и, как правило, будет обновление в последнюю минуту за х> 5 секунд. Кажется справедливым :-) – Stuck

+1

@Stuck: Сделано правильно, этот шаблон будет приятным для батареи. Опять же, определенно используйте 'AlarmManager' для такого рода вещей - таким образом, ваш код может оставаться вне ОЗУ, когда все, что он делает, это ждать следующего события. Если пользователь переключается на сверхбыстрые обновления за последнюю минуту в обратном отсчете, вы должны, вероятно, запустить службу до конца, используя «TimerTask» или что-то еще. Просто не забудьте вызвать 'stopSelf()' на 'Сервис', когда вы закончите с ним, поэтому он отключается и выходит из памяти. – CommonsWare

+0

да, я сделаю это. :-) – Stuck

Смежные вопросы