Я разработал приложение, которое использует много изображений на Android.
Приложение запускается один раз, заполняет информацию на экране ( Layouts
, Listviews
, Textviews
, ImageViews
, и т.д.) и пользователь считывает информацию.
Там нет анимации, никаких спецэффектов или чего-то, что может заполнить память. Иногда ничья может измениться. Некоторые из них - ресурсы Android, а некоторые - файлы, сохраненные в папке на SDCARD.
Затем пользователь завершает работу ( onDestroy
метод выполняется, а приложение остается в памяти виртуальной машиной), а затем в какой-то момент пользователь снова входит в систему.
Каждый раз, когда пользователь входит в приложение, я вижу, как увеличивается и увеличивается объем памяти, пока пользователь не получит java.lang.OutOfMemoryError
.
Итак, что является лучшим / правильным способом обработки множества изображений?
Должен ли я поместить их в статические методы, чтобы они не загружались все время? Нужно ли чистить макет или изображения, используемые в макете, особым образом?
источник
Ответы:
Похоже, у вас утечка памяти. Проблема не в том, что многие изображения обрабатываются, а в том, что ваши изображения не освобождаются, когда ваша деятельность разрушается.
Трудно сказать, почему это происходит, не глядя на ваш код. Однако в этой статье есть несколько советов, которые могут помочь:
http://android-developers.blogspot.de/2009/01/avoiding-memory-leaks.html
В частности, использование статических переменных может ухудшить, а не улучшить ситуацию. Возможно, вам придется добавить код, который удаляет обратные вызовы, когда ваше приложение перерисовывает, - но опять же, здесь недостаточно информации, чтобы сказать наверняка.
источник
Одна из самых распространенных ошибок, которые я обнаружил при разработке Android-приложений, - это ошибка «java.lang.OutOfMemoryError: Размер растрового изображения превышает бюджет виртуальной машины». Я часто обнаруживал эту ошибку в действиях, использующих множество растровых изображений после изменения ориентации: действие уничтожается, создается заново, а макеты «раздуваются» из XML, потребляя память виртуальной машины, доступную для растровых изображений.
Битовые карты в предыдущем макете действий неправильно распределяются сборщиком мусора, поскольку они пересекли ссылки на свои действия. После многих экспериментов я нашел довольно хорошее решение для этой проблемы.
Сначала установите атрибут «id» в родительском представлении макета XML:
Затем в
onDestroy()
методе вашей деятельности вызовитеunbindDrawables()
метод, передав ссылку на родительский вид, а затем выполните aSystem.gc()
.Этот
unbindDrawables()
метод рекурсивно исследует дерево представлений и:источник
Чтобы избежать этой проблемы, вы можете использовать нативный метод
Bitmap.recycle()
передnull
-ingBitmap
object (или установить другое значение). Пример:И затем вы можете изменить
myBitmap
без вызова,System.gc()
как:источник
Я столкнулся с этой точной проблемой. Куча довольно маленькая, поэтому эти изображения могут довольно быстро выйти из-под контроля в отношении памяти. Один из способов - дать сборщику мусора подсказку собирать память на растровом изображении, вызвав его метод recycle .
Кроме того, метод onDestroy не гарантированно вызывается. Возможно, вы захотите перенести эту логику / очистить в действие onPause. Проверьте диаграмму / таблицу жизненного цикла активности на этой странице для получения дополнительной информации.
источник
onPause
предложение. Я использую 4 вкладки сBitmap
изображениями во всех них, поэтому уничтожение активности может произойти не слишком быстро (если пользователь просматривает все вкладки).Это объяснение может помочь: http://code.google.com/p/android/issues/detail?id=8488#c80
«Быстрые советы:
1) НИКОГДА не вызывайте System.gc () самостоятельно. Это было распространено как исправление здесь, и это не работает. Не делать это. Если вы заметили в моем объяснении, перед тем как получить OutOfMemoryError, JVM уже запускает сборку мусора, поэтому нет причин делать это снова (это замедляет работу вашей программы). Выполнение одного в конце вашей деятельности просто прикрывает проблему. Это может привести к тому, что растровое изображение будет помещено в очередь финализатора быстрее, но нет причины, по которой вы не могли бы просто вызвать recycle для каждого растрового изображения.
2) Всегда вызывайте recycle () для растровых изображений, которые вам больше не нужны. По крайней мере, в onDestroy вашей деятельности выполните и переработайте все растровые изображения, которые вы использовали. Кроме того, если вы хотите, чтобы экземпляры растрового изображения собирались из кучи dalvik быстрее, не повредит очистить любые ссылки на растровое изображение.
3) Вызов recycle (), а затем System.gc () все еще не может удалить растровое изображение из кучи Dalvik. НЕ ЗАБУДЬТЕ об этом. recycle () выполнил свою работу и освободил родную память, потребуется лишь некоторое время, чтобы пройти шаги, которые я описал ранее, чтобы фактически удалить растровое изображение из кучи Dalvik. Это не имеет большого значения, потому что большой кусок родной памяти уже свободен!
4) Всегда предполагайте, что в фреймворке последняя ошибка. Dalvik делает именно то, что должен делать. Это может быть не то, что вы ожидаете или чего вы хотите, а то, как это работает. "
источник
У меня была точно такая же проблема. После нескольких испытаний я обнаружил, что эта ошибка появляется при масштабировании большого изображения. Я уменьшил масштаб изображения, и проблема исчезла.
PS Сначала я попытался уменьшить размер изображения, не уменьшая его. Это не остановило ошибку.
источник
Следующие пункты очень помогли мне. Могут быть и другие моменты, но они очень важны:
источник
Я предлагаю удобный способ решения этой проблемы. Просто присвойте атрибуту «android: configChanges» значение, как указано в файле Mainfest.xml, для вашей операции с ошибками. как это:
первое решение, которое я дал, действительно уменьшило частоту ошибок OOM до низкого уровня. Но это не решило проблему полностью. И тогда я выдам 2-е решение:
Как подробно описал OOM, я использовал слишком много оперативной памяти. Итак, я уменьшил размер изображения в ~ / res / drawable моего проекта. Например, переоцененное изображение с разрешением 128х128 можно изменить до 64х64, что также подходит для моего приложения. И после того, как я сделал это с кучей картинок, ошибка OOM больше не возникает.
источник
Я тоже разочарован ошибкой вне памяти. И да, я также обнаружил, что эта ошибка часто появляется при масштабировании изображений. Сначала я попытался создать размеры изображения для всех плотностей, но обнаружил, что это существенно увеличило размер моего приложения. Так что теперь я просто использую одно изображение для всех плотностей и масштабирую свои изображения.
Мое приложение будет выдавать ошибку вне памяти всякий раз, когда пользователь переходит от одного действия к другому. Установка для моих drawables значения null и вызов System.gc () не сработали, равно как и переработка моих bitmapDrawables с помощью getBitMap (). Recycle (). Android будет продолжать выдавать ошибку «outofmemory» при первом подходе, и он будет выдавать сообщение об ошибке «canvas» всякий раз, когда будет пытаться использовать переработанное растровое изображение со вторым подходом.
Я выбрал даже третий подход. Я установил все виды на ноль, а фон - на черный. Я делаю эту очистку в моем методе onStop (). Этот метод вызывается, как только действие перестает быть видимым. Если вы сделаете это в методе onPause (), пользователи увидят черный фон. Не идеально. Что касается этого в методе onDestroy (), нет гарантии, что он будет вызван.
Чтобы предотвратить появление черного экрана, если пользователь нажимает кнопку «Назад» на устройстве, я перезагружаю действие в методе onRestart (), вызывая методы startActivity (getIntent ()) и затем finish ().
Примечание: не обязательно менять фон на черный.
источник
Методы BitmapFactory.decode *, описанные в уроке « Загрузка больших растровых изображений эффективно» , не должны выполняться в главном потоке пользовательского интерфейса, если исходные данные считываются с диска или из сетевого расположения (или действительно из любого источника, кроме памяти). Время загрузки данных непредсказуемо и зависит от множества факторов (скорость чтения с диска или сети, размер изображения, мощность процессора и т. Д.). Если одна из этих задач блокирует поток пользовательского интерфейса, система помечает ваше приложение как неотвечающее, и пользователь может закрыть его (для получения дополнительной информации см. Проектирование для отзывчивости).
источник
Ну, я перепробовал все, что нашел в интернете, и ни один из них не сработал. Вызов System.gc () только снижает скорость приложения. Утилизация растровых изображений в onDestroy не работает для меня тоже.
Единственное, что работает сейчас - это иметь статический список всех растровых изображений, чтобы растровые изображения сохранялись после перезапуска. И просто используйте сохраненные растровые изображения вместо создания новых каждый раз, когда действие перезапускается.
В моем случае код выглядит так:
источник
У меня была такая же проблема только с переключением фоновых изображений с разумными размерами. Я получил лучшие результаты, установив для ImageView значение null, прежде чем вставлять новое изображение.
источник
Кстати, вот легкий растровый кэш, который я кодировал и использовал в течение нескольких месяцев. Это не все навороты, поэтому прочитайте код, прежде чем использовать его.
источник