Как повысить производительность для resources.getDrawable

У меня есть активность, которая загружает три изображения png. На hdpi это 20кб, 148кб и 190кб. Вот код, которым я их загружаю:

Drawable bronzePlaque = resources.getDrawable(R.drawable.bronze_plaque);
Drawable silverPlaque = resources.getDrawable(R.drawable.silver_plaque);
Drawable goldPlaque = resources.getDrawable(R.drawable.gold_plaque);

Одни только эти вызовы занимают около 500 мс, что вызывает заметную задержку при загрузке этой активности.

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

Вот вывод logcat для этих трех строк (и для системы выведите getTimeInMillis вокруг них).

03-23 14:05:57.260: I/System.out(30302): time: 1395608757267
03-23 14:05:57.370: D/dalvikvm(30302): GC_FOR_ALLOC freed 39K, 4% free 7990K/8272K, paused 20ms, total 20ms
03-23 14:05:57.370: I/dalvikvm-heap(30302): Grow heap (frag case) to 8.968MB for 1188160-byte allocation
03-23 14:05:57.390: D/dalvikvm(30302): GC_FOR_ALLOC freed 1K, 4% free 9149K/9436K, paused 19ms, total 19ms
03-23 14:05:57.540: D/dalvikvm(30302): GC_FOR_ALLOC freed 1K, 4% free 9148K/9436K, paused 15ms, total 16ms
03-23 14:05:57.540: I/dalvikvm-heap(30302): Grow heap (frag case) to 10.245MB for 1340008-byte allocation
03-23 14:05:57.560: D/dalvikvm(30302): GC_FOR_ALLOC freed <1K, 3% free 10457K/10748K, paused 19ms, total 19ms
03-23 14:05:57.720: D/dalvikvm(30302): GC_FOR_ALLOC freed <1K, 3% free 10457K/10748K, paused 15ms, total 15ms
03-23 14:05:57.720: I/dalvikvm-heap(30302): Grow heap (frag case) to 11.482MB for 1297384-byte allocation
03-23 14:05:57.740: D/dalvikvm(30302): GC_FOR_ALLOC freed <1K, 3% free 11724K/12016K, paused 18ms, total 18ms
03-23 14:05:57.760: I/System.out(30302): time: 1395608757770

Я знаю, что после того, как эта активность была загружена, она намного быстрее загружается позже. Должен ли я загружать эти изображения один раз во время загрузки приложения, чтобы предотвратить болезненный рост кучи/сбор мусора? Я бы предпочел, чтобы эти полсекунды задержки были загружены вперед, чем при нажатии на действие.


person CorayThan    schedule 23.03.2014    source источник
comment
Какого размера изображения?   -  person Simon    schedule 24.03.2014
comment
750 x 502 пикс. -- 20 КБ, 750 x 567 пикс. -- 149 КБ и 750 x 549 пикс. -- 190 КБ. Это фоновые изображения для прокрутки.   -  person CorayThan    schedule 24.03.2014


Ответы (2)


Попробуйте вместо этого загрузить эти изображения из другого потока (то есть не из основного). Помимо ~ 100 мс, потраченных на gc, остальные 500 мс тратятся на загрузку данных из файловой системы и распаковку данных JPG в растровые изображения.

Я знаю, что после того, как эта активность была загружена, она намного быстрее загружается позже. Должен ли я загружать эти изображения один раз во время загрузки приложения, чтобы предотвратить болезненный рост кучи/сбор мусора?

Если вы намеренно не удерживали декодированные растровые изображения, в противном случае Resources может свободно выпускать любые кэшированные Drawable/Bitmap, которые он считает нужными. Обратите внимание, что образы будут занимать 750 x 502 x 4 + 750 x 567 x 4 + 750 x 549 x 4 = ~ 4,5 МБ ОЗУ, их намеренное хранение может иметь другие последствия, такие как OoM на старых устройствах (Nexus One имеет максимум 16 МБ ОЗУ на процесс/приложение) и может привести к тому, что ваше приложение будет удалено из памяти раньше, когда оно находится в фоновом режиме, а ОС требуется больше оперативной памяти.

person Kai    schedule 24.03.2014
comment
Да я и не хочу их держать. На данный момент я просто загружаю их в метод onCreate для приложения, что, кажется, непоследовательно немного уменьшает боль. Активность не может отображаться до тех пор, пока они не будут загружены, поэтому загрузка их в другом потоке не принесет много пользы, если только я не захочу сделать анимацию загрузки или что-то в этом роде. - person CorayThan; 26.03.2014
comment
@CorayThan Если вы действительно заинтересованы в сокращении времени загрузки, и это действие не является основным действием, вы можете загрузить необработанные данные файла в память как byte[], чтобы вам не нужно было загружать их при запуске этого конкретного действия. Очевидно, что перед тем, как идти по этому пути, вы должны проверить часть чтения файлов, чтобы убедиться, что в этом есть польза. - person Kai; 26.03.2014

Похоже, вам немного не повезло. Вы не можете увеличивать кучу на Android по своему желанию (в отличие от обычного процесса JVM). См. здесь Тем не менее изображения размером 4 МБ — это слишком много.

И похоже, что у вас уже есть решение, загрузите его заранее.

person Eugene    schedule 25.03.2014