Как загрузить большие изображения в Android и избежать ошибки из памяти?

Я работаю над приложением, которое использует большие изображения (1390 × 870: 150kb – 50kb). Я добавляю изображения при нажатии триггера / ImageView.

В какой-то момент у меня возникает ошибка в памяти:

java.lang.OutOfMemoryError E/AndroidRuntime(23369): at android.graphics.BitmapFactory.nativeDecodeStream(Native Method) E/AndroidRuntime(23369): at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:613) E/AndroidRuntime(23369): at android.graphics.BitmapFactory.decodeFile(BitmapFactory.java:378) 

Чтобы resize изображения, я делаю это:

 Bitmap productIndex = null; final String imageLoc = IMAGE_LOCATION; InputStream imageStream; try { imageStream = new FileInputStream(imageLoc); productIndex = decodeSampledBitmapFromResource(getResources(), imageLoc, 400, 400); productIV.setImageBitmap(productIndex); } catch (FileNotFoundException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } } public static Bitmap decodeSampledBitmapFromResource(Resources res, String resId, int reqWidth, int reqHeight) { // First decode with inJustDecodeBounds=true to check dimensions final BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; BitmapFactory.decodeFile(resId, options); // Calculate inSampleSize options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight); // Decode bitmap with inSampleSize set options.inJustDecodeBounds = false; return BitmapFactory.decodeFile(resId, options); } public static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) { // Raw height and width of image final int height = options.outHeight; final int width = options.outWidth; int inSampleSize = 1; if (height > reqHeight || width > reqWidth) { final int halfHeight = height / 3; final int halfWidth = width / 3; // Calculate the largest inSampleSize value that is a power of 2 and keeps both // height and width larger than the requested height and width. while ((halfHeight / inSampleSize) > reqHeight && (halfWidth / inSampleSize) > reqWidth) { inSampleSize *= 2; } } return inSampleSize; } 

Я получил такой способ изменения размера, чтобы сэкономить место в Android-документах: эффективно загружать большие растровые изображения

Согласно журналу это похоже на виновника метода decodeSampledBitmapFromResource :

 return BitmapFactory.decodeFile(resId, options); 

—– edit —– Вот как я добавляю каждый элемент в FrameLayout.

 for(int ps=0;ps<productSplit.size();ps++){ //split each product by the equals sign List productItem = Arrays.asList(productSplit.get(ps).split("=")); String tempCarID = productItem.get(0); tempCarID = tempCarID.replace(" ", ""); if(String.valueOf(carID).equals(tempCarID)){ ImageView productIV = new ImageView(Configurator.this); LayoutParams productParams = new LayoutParams( LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT); productIV.setId(Integer.parseInt(partIdsList.get(x))); productIV.setLayoutParams(productParams); final String imageLoc = productItem.get(2); InputStream imageStream; try { imageStream = new FileInputStream(imageLoc); productIndex = decodeSampledBitmapFromResource(getResources(), imageLoc, 400, 400); productIV.setImageBitmap(productIndex); } catch (FileNotFoundException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } productLayers.addView(productIV); } } 

Вы можете использовать другой bitmap-config для значительного уменьшения размера изображений. По умолчанию используется RGB-config ARGB8888, что означает использование четырех 8-битных каналов (красный, зеленый, синий, alhpa). Альфа – прозрачность растрового изображения. Это занимает много памяти – изображение X 4. Так что если изображение будет 4 мегапикселя, 16 мегабайт будет сразу же распределено на куче – быстро изнурительная память.

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

Итак – к вашему методу decodeSampledBitmapFromResource – добавьте следующие fragmentы:

  options.inPreferredConfig = Config.RGB_565; options.inDither = true; 

В вашем коде:

  public static Bitmap decodeSampledBitmapFromResource(Resources res, String resId, int reqWidth, int reqHeight) { // First decode with inJustDecodeBounds=true to check dimensions final BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; BitmapFactory.decodeFile(resId, options); // Calculate inSampleSize options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight); // Decode bitmap with inSampleSize set options.inJustDecodeBounds = false; options.inPreferredConfig = Config.RGB_565; options.inDither = true; return BitmapFactory.decodeFile(resId, options); } 

Рекомендации:

http://developer.android.com/reference/android/graphics/Bitmap.Config.html#ARGB_8888

У устройств с высоким разрешением, таких как S4, обычно заканчивается память, если у вас нет изображения в соответствующей папке, которая является drawable-xxhdpi . Вы также можете поместить свое изображение в drawable-nodpi . Причина, по которой она закончилась бы из воспоминаний, если бы ваш образ просто мог бы сделать это, чтобы андроид масштабировал изображение, думая, что изображение было спроектировано для низкого разрешения.

Вы можете использовать эту красивую библиотеку https://github.com/davemorrissey/subsampling-scale-image-view

Here is how I'm adding each item to the FrameLayout , это проблема, код продолжает добавлять и добавлять больше изображений, и не имеет значения, насколько хорошо вы изменяете размер или объем памяти устройства, в какой-то момент он закончится Память. Это потому, что каждое изображение, которое вы добавляете, хранится в памяти.

Для такого типа ситуаций приложениями является использование ViewGroup, которое может перерабатывать представления. Я не знаю вашего макета, но обычно это ListView , GridView или ViewPager , перерабатывая представления, которые вы повторно используете макет, и при необходимости можете повторно загружать изображения.

Для конкретной цели загрузки и изменения размеров изображений я настоятельно рекомендую использовать библиотеку Picasso, поскольку она ОЧЕНЬ хорошо написана, проста в использовании и стабильна.

Вам по-прежнему потребуется управлять растровой памятью, так как я бы не пытался выделять общее пространство более чем в 3 раза по размеру экрана (если вы думаете об этом имеет смысл для поведения прокрутки). Если вы накладываете одно изображение поверх другого, в какой-то момент вы получаете ошибку Out Of Memory. Возможно, вам придется посмотреть на захват предыдущего изображения экрана в виде одного фонового изображения, чтобы убедиться, что вы все еще вписываетесь в доступную память. Или когда новое изображение перекрывает существующее изображение, загружает только и визуализирует видимую часть. Если производительность становится проблемой, вам может потребоваться рассмотреть OpenGL Textures, но проблема с распределением памяти остается прежней.

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

Использование библиотеки Fresco для загрузки больших изображений позволит избежать этой ошибки. в XML-макете

  

и в джавакоде

 Uri uri = Uri.parse("http://sofru.miximages.com/android/image.png"); SimpleDraweeView draweeView = (SimpleDraweeView) findViewById(R.id.my_image_view); draweeView.setImageURI(uri); 
  • Ссылки в TextView
  • Запись / чтение файлов в / из внутренней памяти телефона Android
  • Использование цвета и color.darker в Android?
  • Как запустить / запустить приложение во время загрузки Android
  • Android: ошибка в launchMode = "singleTask"? -> стек активности не сохранен
  • Как resize изображения (битмап) до заданного размера?
  • Зарегистрировать новый тип файла в Android
  • Layout Layers? Z-Axis?
  • AVD - PANIC: Не удалось открыть ... - не проблема
  • как обрабатывать несколько classов приложений в android
  • как определить ориентацию устройства Android?
  • Interesting Posts

    Угловой ng-стиль с условным выражением

    Компьютер запускается без нажатия кнопки питания

    Какова область по умолчанию для рабочих листов и ячеек и диапазона?

    SSRS – Как создать простой отчет с несколькими столбцами?

    Как получить текущий момент в формате ISO 8601 с датой, часом и минутой?

    При каких обстоятельствах SqlConnection автоматически включается в транзакцию TransactionScope?

    Использует импорт ES6 для загрузки определенных имен быстрее, чем импорт пространства имен?

    Консоль менеджера пакетов Enable-Migrations CommandNotFoundException только в конкретном проекте VS

    Странная ошибка firefox

    Как кэшировать растровые изображения в встроенную память

    Полностью отключить UAC в Windows 10

    Как проверить доступное пространство на устройстве Android? на SD-карте?

    Эквивалент для Windows 7 «mklink» на OS X?

    Жесткий диск Seagate 3TB ST3000DM001, не распознанный Linux, вызывает зависание fdisk

    Управление объемами различных программ

    Давайте будем гением компьютера.