Проблемы с производительностью при обновлении нескольких элементов интерфейса каждую секунду - PullRequest
0 голосов
/ 01 марта 2012

РЕДАКТИРОВАТЬ : я разместил свое решение ниже (в основном, ListViews очень медленный по некоторым причинам), и постараюсь обновить его, если я смогу объяснить, почему именно ListView так ужасен в эта ситуация.

Цель:

Получить 7 объектов ListView, показывающих 7 независимо установленных часов / таймеров, которые обновляются / отмечаются каждую секунду. Эти часы являются просто строками с показанным рассчитанным прошедшим временем (SystemClock.ElapsedRealTime () - хранится ElapsedRealTime (), когда был создан объект.)

Проблема:

По существу, 8 минут из этих 7 часов тикают - моя программа по сути бесполезна ... представленная информация является неточной, пользовательский интерфейс в значительной степени не отвечает и т. Д. Вот некоторые результаты тестирования с эталоном физического секундомера:

  • В 04:00 часы смещаются на 1 секунду и обновляются каждые 4 секунды.
  • В 06:00 часы проскальзывают на 3 секунды и обновляются каждые 5 секунд.
  • В 08:00 часы проскальзывают на 6-7 секунд и обновляются каждые 6 секунд.
  • В 16:00 часы проскальзывают на 7 секунд и обновляются каждые 10 секунд.

Что у меня пока есть:

У меня есть собственный класс ActivityTimer, с сохраненным long, представляющим SystemClock.ElapsedRealTime () того времени, когда каждый экземпляр ActivityTimer был впервые создан. Нажав на кнопку 7 раз, я создаю 7 экземпляров, каждый из которых добавляется в ArrayList

У меня есть составное представление ActivityTimerControl, которому передают экземпляр ActivityTimer при создании экземпляра, а затем представляют элементы данных моего ActivityTimer в элементах пользовательского интерфейса (например, тикающие часы). Мой ArrayAdapter обрабатывает это создание и работает нормально. Согласно этому прекрасному учебнику у меня есть _Handler в этом ActivityControl, который при создании ActvityControl публикует это:

private Runnable _timerUpdateTask = new Runnable() 
{
    public void run() 
    {
        final long start = _ActivityTimer.getStartTime();
        long millis = SystemClock.elapsedRealtime() - start;
        int seconds = (int) (millis / 1000);
        int minutes = seconds / 60;
        seconds     = seconds % 60;
        if (seconds < 10) 
        {
            _tglActivityPauseButton.setTextOn(""+minutes+":0"+seconds);
        } 
        else 
        {
            _tglActivityPauseButton.setTextOn("" + minutes + ":" + seconds);            
        }
        _tglActivityPauseButton.setChecked(true);
        _timerUpdateHandler.postDelayed(this, 1000);
        }
};

Кроме того, что я описал, мой проект на самом деле ничего не делает, так как я до сих пор застрял в этой фундаментальной проблеме. Так что я не опубликовал никакого другого кода, потому что я не думаю, что он уместен за пределами приведенных выше резюме, но если кто-то считает, что какая-то другая часть проекта актуальна, просто дайте мне знать, и я опубликую подробный код для этого. Я представляю свою последнюю строку в SetTextOn () ToggleButton, но тестирование показало, что это не является существенным фактором - не имеет значения, устанавливаю ли я текст обычного TextView, или что, нет Независимо от того, что я пробовал, мои результаты всегда примерно одинаковы, с заметной задержкой на каждом такте и, в конечном итоге, пользовательский интерфейс полностью не отвечает.

Насколько я понимаю, предполагается, что обработчик является наиболее эффективным способом обновления элемента пользовательского интерфейса на постоянной и частой основе, заменяя java.util.Timer, но, несмотря на это, мой код запускается медленно и становится хуже, чем дольше Я позволил ему бежать.

Даже после увеличения postDelay до 5000 мс, те же проблемы все еще возникали, и приложение по-прежнему принудительно закрывалось через 49 минут. Так как я бы подумал, что этот тест увеличил бы время до принудительного закрытия на 5, если бы он не был исправлен полностью (в ущерб нужной мне функциональности), я подозреваю, что что-то неправильно обрабатывается с помощью обработчика или какой-то другой компонент.

Мои вопросы:

  • Я подозреваю, что моя проблема в том, что у меня есть 7 объектов (ActivityControls), каждый из которых имеет свой собственный обработчик , постоянно повторяющий обновление соответствующего времени, которое отображается. У кого-нибудь есть опыт, чтобы сказать, будет ли это так?
  • Есть ли способ, которым я могу иметь один обработчик, который вызывает каждый ActivityControl в моем ListView для обновления своего времени?
  • Оставляет ли сообщение в обработчике какую-то трассировку памяти, которая не удаляется автоматически, или может принести пользу от вынужденной утилизации?
  • У кого-нибудь еще есть идеи относительно наиболее эффективного способа запуска постоянных обновлений пользовательского интерфейса для нескольких объектов?

Ответы [ 2 ]

0 голосов
/ 01 марта 2012

Тьфу ... разве вы не знаете это ... это не проблема с моим обработчиком, или что-нибудь еще в этом роде. Это либо неэффективность с ListView, либо какая-то забавность, которая имеет место в ArrayAdapter (тот, который я использовал, был настолько прост, насколько это возможно.) Я сделал проект песочницы (ниже) и создал свои 7 ActivityTimers прямо в ArrayList, а затем итерацию по этому массиву с использованием каждого объекта для создания экземпляра ActivityControl, который передал копию этого ActivityTimer из массива. Все, что я делал ранее, но заменил ListView на LinearLayout, содержащийся в ScrollView. Через 16 минут у меня есть 7 ActivityControls, тикающих примерно каждую секунду, и сохраняющих точное время. Даже через 30 минут не было ни малейшего намека на проблемы (как и должно быть!) Вот что я сделал:

public class Sandbox_Experiments extends Activity {
ArrayList<com.maxx233.Sandbox.ActivityTimer> _ActivityTimers = null;

@Override
public void onCreate(Bundle savedInstanceState) 
{
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    _ActivityTimers = new ArrayList<com.maxx233.Sandbox.ActivityTimer>();
    View myLayout =  findViewById(R.id.Info);

    com.maxx233.Sandbox.ActivityTimer act1 = new com.maxx233.Sandbox.ActivityTimer();
    com.maxx233.Sandbox.ActivityTimer act2 = new com.maxx233.Sandbox.ActivityTimer();
    com.maxx233.Sandbox.ActivityTimer act3 = new com.maxx233.Sandbox.ActivityTimer();
    com.maxx233.Sandbox.ActivityTimer act4 = new com.maxx233.Sandbox.ActivityTimer();
    com.maxx233.Sandbox.ActivityTimer act5 = new com.maxx233.Sandbox.ActivityTimer();
    com.maxx233.Sandbox.ActivityTimer act6 = new com.maxx233.Sandbox.ActivityTimer();
    com.maxx233.Sandbox.ActivityTimer act7 = new com.maxx233.Sandbox.ActivityTimer();


    _ActivityTimers.add(act1);
    __ActivityTimers.add(act2);
    __ActivityTimers.add(act3);
    __ActivityTimers.add(act4);
    __ActivityTimers.add(act5);
    __ActivityTimers.add(act6);
    __ActivityTimers.add(act7);


    for (int i = 0; i < __ActivityTimers.size(); i++)
    {
        ActivityControl ac = new ActivityControl(this, (com.maxx233.Sandbox.ActivityTimer)__ActivityTimers.get(i));
        ac.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.FILL_PARENT, LinearLayout.LayoutParams.FILL_PARENT));
        ((LinearLayout)myLayout).addView(ac);
    }
}

}

Так что я буду работать над выяснением того, что конкретно относится к ListView в уравнении, которое вызывает такую ​​проблему, а затем я обновлю эту ветку на случай, если у кого-нибудь еще возникнет подобная проблема. Если кто-то еще там не знает, почему ListView делает обновление горстки объектов каждую секунду намного более ресурсоемким?

0 голосов
/ 01 марта 2012

вы задерживаетесь на 1сек

_timerUpdateHandler.postDelayed (this, 1000);

Вы не разрешили в любое время запустить ваш код.

...