Несколько TextViews обновляются очень медленно

У меня есть Служба, которая отправляет Intent на мою активность каждые 0,1 секунды. Я использую его для обновления пользовательской реализации хронометра. Здесь все идет правильно. Проблема возникает, когда я хочу обновить 14 TextView, которые у меня есть в TableView внутри фрагмента в моей работе. Здесь приложение очень медленно.

Метод в моей деятельности, где он получает намерение от Сервиса:

private BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
        long milis = intent.getLongExtra("milis",0);
        if( mFragment != null)
        mFragment.Update(milis);
    }
};

Код внутри Фрагмента, где я обновляю TextViews:

public void actualizarTiempoJuego(long milis){
    // Se recuperan los tiempos acumulados y se aumenta la cantidad pasada como parámetro
    for(int i=0;i<7;++i) {
        long mCurrentMilis1 = mVectorMilis1.get(i);
        long mCurrentMilis2 = mVectorMilis2.get(i);
        TextView1 t1 = mListaTitularLayoutLocal.get(i);
        TextView1 t2 = mListaTitularLayoutVisitante.get(i);
        t1.setText(String.value(milis + mCurrentMilis1));
        t2.setText(String.value(milis + mCurrentMilis2));
    }
}

Я делаю что-то не так, или просто я пытаюсь сделать что-то очень сложное с точки зрения эффективности?

Ответ 1

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

<application android:hardwareAccelerated="true"... />

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

Для этой проблемы мне нравится использовать Handlers. Они более легкие, чем намерения. Вы также можете посмотреть AsyncTask. Это в основном как поток, но также дает перехваты, которые запускаются в потоке пользовательского интерфейса, поэтому вы можете выполнять как фоновое действие, так и обновлять пользовательский интерфейс без необходимости отправлять runnables.

EDIT: Наконец, вы всегда можете запускать свои макеты с помощью layoutopt. Мне лично рассказал сам Ромен Гай, что если ваш рисунок слишком медленный, вам нужно меньше рисовать. Просто просмотрите скриншот (из дерева с минимальным представлением, но хорошо в пределах max) из инструмента профилирования. Вы можете видеть, сколько занимает рисование ресурсов. Очень важно держать это как можно более тонкими, если вы хотите, чтобы ваше приложение было отзывчивым. Profiling View Drawing Resource Consumption

EDIT: он больше не называется layoutopt, он называется lint. Проверьте свой файл ~/android-sdk/tools/

Ответ 2

Я когда-то сталкивался с ситуацией, когда фрагмент был очень медленным.

Я просто предсказываю, что ваш фрагмент имеет какую-то альфу и нарисован на "тяжелой" активности.

Вывод: каждый раз, когда вы устанавливаете текст текстового представления, вся ваша иерархия представлений недействительна.

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


ДОПОЛНЕНИЕ: текстовое представление wrap_content приведет к значительно большей задержке после setText, чем текстовое представление fill_parent.

Ответ 3

Вероятно, вы столкнулись с замедлением из-за управления компоновкой с помощью TableLayout и TextView. Каждый раз, когда вы обновляете текст в одном из них, должно выполняться большое количество измерений, чтобы помещать символы в нужное место на экране. Вы действительно должны просто профилировать приложение самостоятельно, используя Traceview, чтобы узнать. Дополнительная информация: http://developer.android.com/tools/debugging/debugging-tracing.html

У меня была та же самая проблема, которую вы видите с тем же типом макета (Fragment > TableLayout > Multiple TextViews). Один из способов проверить, является ли ваша установка TableLayout/TextView виной, - это просто заменить все это одним TextView. Это, вероятно, будет работать очень хорошо. Затем добавьте 14 просмотров в FrameLayout или RelativeLayout. Даже если все они перекрываются, вы все равно должны получать приличную производительность, потому что это сложность измерений в представлении TableLayout, которые действительно приводят к замедлению.

Ответ 4

Как кто-то сказал, что вы можете использовать HardwareAccelerated, но это не отличное решение, вы будете тратить баран и процессор, если вы не сможете решить его по-другому. Решение, вероятно, более безопасно, чтобы уменьшить количество TextView. Попытайтесь уменьшить 14 до 7, и он будет идти в два раза быстрее. Обычно это сложно сделать, но если вы поместите объекты в положение стратегии, пара TextView один над другим может быть вместе, если вы создадите TextView с двумя строками. И не забывайте, что findViewById так дорого, если вы будете использовать объект вида, часто его можно найти один раз и сохранить его ссылку.

Ответ 5

Тесты всегда полезны для определения того, откуда на самом деле происходит медлительность, но я уверен, что предложение Intent, вероятно, намного медленнее, чем обновление 14 TextView. Отправка 10 намерений в секунду - это знак того, что вы делаете это неправильно (TM). Это не то, для чего они предназначены.

Я делаю что-то не так, или просто я пытаюсь сделать что-то очень сложное с точки зрения эффективности?

Обновление 14 TextViews в секунду не является по своей сути сложным; вы должны быть в состоянии легко достичь этого с помощью более подходящего дизайна приложения. ASyncTask или Handler приходят на ум но трудно понять, что лучше, не зная больше о том, что вы пытаетесь сделать.

Ответ 6

  • Вы можете попытаться объявить vars вне цикла:

    public void actualizarTiempoJuego(long milis){
        // Se recuperan los tiempos acumulados y se 
        // aumenta la cantidad pasada como parámetro
    
        long mCurrentMilis1;
        long mCurrentMilis2;
        TextView1 t1;
        TextView1 t2;
    
        for(int i=0;i<7;++i) {
            mCurrentMilis1 = mVectorMilis1.get(i);
            mCurrentMilis2 = mVectorMilis2.get(i);
            t1 = mListaTitularLayoutLocal.get(i);
            t2 = mListaTitularLayoutVisitante.get(i);
            t1.setText(String.value(milis + mCurrentMilis1));
            t2.setText(String.value(milis + mCurrentMilis2));
        }
    }
    
  • И до setText() со смешанным типом вы можете попробовать setText("" + milis + mCurrentMilis2);