Странный из выпуска памяти во время загрузки изображения на объект Bitmap

голоса
1k

У меня есть представление списка с парой кнопок изображения на каждой строке. При нажатии на строку списка, он запускает новый вид деятельности. Я должен был построить свои собственные вкладки из - за проблемы с компоновкой камеры. Деятельность , которая получает запущен в результате это карта. Если я нажимаю на моей кнопку для запуска предварительного просмотра изображения (загрузить изображение от SD - карты) возвращается приложение от деятельности назад к listviewдеятельности в обработчик результата , чтобы возобновить свою новую деятельность , которая является не более чем виджет изображения.

Изображение для предварительного просмотра на экране списка делается с курсором и ListAdapter. Это делает его довольно просто, но я не знаю , как я могу поставить уменьшенное изображение (то есть меньшего размера бит не пиксель как srcдля кнопки изображения на лету. Так что я просто изменил размер изображения, оторвались камеру телефона.

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

  • Есть ли способ я могу построить адаптер список легко грести по строкам, где я могу изменить размер на лету ( немного мудрой )?

Это было бы предпочтительнее , так как мне нужно внести некоторые изменения в свойствах виджетов / элементов в каждой строке , как я не могу выбрать строку с сенсорным экраном , так как фокус вопроса. ( Я могу использовать роллер. )

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

Как только я отключил изображение на экране списка он работал нормально снова.

FYI: Это, как я это делал:

String[] from = new String[] { DBHelper.KEY_BUSINESSNAME,DBHelper.KEY_ADDRESS,DBHelper.KEY_CITY,DBHelper.KEY_GPSLONG,DBHelper.KEY_GPSLAT,DBHelper.KEY_IMAGEFILENAME  + };
int[] to = new int[] {R.id.businessname,R.id.address,R.id.city,R.id.gpslong,R.id.gpslat,R.id.imagefilename };
notes = new SimpleCursorAdapter(this, R.layout.notes_row, c, from, to);
setListAdapter(notes);

Где R.id.imagefilenameэто ButtonImage.

Вот мой LogCat:

01-25 05:05:49.877: ERROR/dalvikvm-heap(3896): 6291456-byte external allocation too large for this process.
01-25 05:05:49.877: ERROR/(3896): VM wont let us allocate 6291456 bytes
01-25 05:05:49.877: ERROR/AndroidRuntime(3896): Uncaught handler: thread main exiting due to uncaught exception
01-25 05:05:49.917: ERROR/AndroidRuntime(3896): java.lang.OutOfMemoryError: bitmap size exceeds VM budget
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.graphics.BitmapFactory.nativeDecodeStream(Native Method)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:304)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.graphics.BitmapFactory.decodeFile(BitmapFactory.java:149)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.graphics.BitmapFactory.decodeFile(BitmapFactory.java:174)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.graphics.drawable.Drawable.createFromPath(Drawable.java:729)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.widget.ImageView.resolveUri(ImageView.java:484)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.widget.ImageView.setImageURI(ImageView.java:281)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.widget.SimpleCursorAdapter.setViewImage(SimpleCursorAdapter.java:183)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.widget.SimpleCursorAdapter.bindView(SimpleCursorAdapter.java:129)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.widget.CursorAdapter.getView(CursorAdapter.java:150)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.widget.AbsListView.obtainView(AbsListView.java:1057)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.widget.ListView.makeAndAddView(ListView.java:1616)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.widget.ListView.fillSpecific(ListView.java:1177)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.widget.ListView.layoutChildren(ListView.java:1454)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.widget.AbsListView.onLayout(AbsListView.java:937)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.view.View.layout(View.java:5611)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1119)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.widget.LinearLayout.layoutHorizontal(LinearLayout.java:1108)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.widget.LinearLayout.onLayout(LinearLayout.java:922)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.view.View.layout(View.java:5611)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.widget.FrameLayout.onLayout(FrameLayout.java:294)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.view.View.layout(View.java:5611)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1119)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.widget.LinearLayout.layoutVertical(LinearLayout.java:999)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.widget.LinearLayout.onLayout(LinearLayout.java:920)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.view.View.layout(View.java:5611)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.widget.FrameLayout.onLayout(FrameLayout.java:294)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.view.View.layout(View.java:5611)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.view.ViewRoot.performTraversals(ViewRoot.java:771)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.view.ViewRoot.handleMessage(ViewRoot.java:1103)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.os.Handler.dispatchMessage(Handler.java:88)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.os.Looper.loop(Looper.java:123)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.app.ActivityThread.main(ActivityThread.java:3742)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at java.lang.reflect.Method.invokeNative(Native Method)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at java.lang.reflect.Method.invoke(Method.java:515)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:739)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:497)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at dalvik.system.NativeStart.main(Native Method)
01-25 05:10:01.127: ERROR/AndroidRuntime(3943): ERROR: thread attach failed 

У меня также есть новая ошибка при отображении изображения:

01-25 22:13:18.594: DEBUG/skia(4204): xxxxxxxxxxx jpeg error 20 Improper call to JPEG library in state %d
01-25 22:13:18.604: INFO/System.out(4204): resolveUri failed on bad bitmap uri: 
01-25 22:13:18.694: ERROR/dalvikvm-heap(4204): 6291456-byte external allocation too large for this process.
01-25 22:13:18.694: ERROR/(4204): VM won't let us allocate 6291456 bytes
01-25 22:13:18.694: DEBUG/skia(4204): xxxxxxxxxxxxxxxxxxxx allocPixelRef failed
Задан 25/01/2009 в 12:23
источник пользователем
На других языках...                            


41 ответов

голоса
849

Чтобы исправить ошибку OutOfMemory, вы должны сделать что-то вроде этого:

BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 8;
Bitmap preview_bitmap = BitmapFactory.decodeStream(is, null, options);

Эта inSampleSizeопция снижает потребление памяти.

Вот полный метод. Сначала он считывает размер изображения без декодирования самого контента. Затем она находит самое лучшее inSampleSizeзначение, то оно должно быть степенью 2, и , наконец , изображение декодируется.

// Decodes image and scales it to reduce memory consumption
private Bitmap decodeFile(File f) {
    try {
        // Decode image size
        BitmapFactory.Options o = new BitmapFactory.Options();
        o.inJustDecodeBounds = true;
        BitmapFactory.decodeStream(new FileInputStream(f), null, o);

        // The new size we want to scale to
        final int REQUIRED_SIZE=70;

        // Find the correct scale value. It should be the power of 2.
        int scale = 1;
        while(o.outWidth / scale / 2 >= REQUIRED_SIZE && 
              o.outHeight / scale / 2 >= REQUIRED_SIZE) {
            scale *= 2;
        }

        // Decode with inSampleSize
        BitmapFactory.Options o2 = new BitmapFactory.Options();
        o2.inSampleSize = scale;
        return BitmapFactory.decodeStream(new FileInputStream(f), null, o2);
    } catch (FileNotFoundException e) {}
    return null;
}
Ответил 05/05/2009 в 10:00
источник пользователем

голоса
543

Android Учебный класс, « Отображение растровых изображений эффективны », предлагает некоторую большую информацию для понимания и решения , за исключением java.lang.OutOfMemoryError: bitmap size exceeds VM budgetпри загрузке Bitmaps.


Читать Bitmap Размеры и тип

BitmapFactoryКласс предоставляет несколько методов декодирования ( decodeByteArray(), decodeFile(), decodeResource(), и т.д.) для создания Bitmapиз различных источников. Выберите наиболее подходящий метод декодирования , основанный на источнике данных изображения. Эти методы пытаются выделить память для растрового изображения , построенного и , следовательно , могут легко привести к OutOfMemoryисключению. Каждый тип метода декодирования имеет дополнительные подписи , которые позволяют задать параметры декодирования с помощью BitmapFactory.Optionsкласса. Установка inJustDecodeBoundsсвойства в trueто время декодирования позволяет избежать выделения памяти, возвращая nullдля растрового объекта , но настройки outWidth, outHeightи outMimeType. Этот метод позволяет считывать размеры и тип данных изображения до начала строительства (и выделения памяти) битовой карты.

BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(getResources(), R.id.myimage, options);
int imageHeight = options.outHeight;
int imageWidth = options.outWidth;
String imageType = options.outMimeType;

Для того, чтобы избежать java.lang.OutOfMemoryисключений, перед декодированием его, если вы абсолютно доверяете источнику , чтобы предоставить вам данные предсказуемо размер изображения , что удобно помещается в пределах доступной памяти проверьте размеры растрового изображения.


Загрузите уменьшенную версию в память

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

  • Расчетное потребление памяти загрузки полного изображения в памяти.
  • Объем памяти, вы готовы совершить загрузку изображения для любых других требований к памяти вашего приложения.
  • Размеры компоненты целевой ImageView или UI, что изображение должны быть загружены в.
  • Размер экрана и плотность тока устройства.

Например, это не стоит загрузки 1024x768 пикселя изображения в память , если он будет в конечном итоге будет отображаться в 128x96 пикселей в миниатюре ImageView.

Для того, чтобы сказать , декодер субсемплировать изображение, загружая уменьшенную версию в память, набор inSampleSizeдля trueвашего BitmapFactory.Optionsобъекта. Например, изображение с разрешением 2048х1536 , что декодируют с inSampleSize4 производит растровое изображение приблизительно 512x384. Загрузка этого в память использует 0.75MB , а не 12MB для полного изображения ( в предположении конфигурации растровой ARGB_8888). Вот метод для вычисления значения размера выборки , которое является степенью два на основе целевой ширины и высоты:

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 / 2;
        final int halfWidth = width / 2;

        // 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;
}

Примечание : степень двойки значения вычисляется , так как декодер использует конечное значение путем округления до ближайшей степени двух, в соответствии с inSampleSizeдокументацией.

Чтобы использовать этот метод, сначала расшифровывают с inJustDecodeBoundsнабором для true, передавать параметры через и затем декодировать снова с использованием нового inSampleSizeзначения и inJustDecodeBoundsустанавливаются на false:

public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId,
    int reqWidth, int reqHeight) {

    // First decode with inJustDecodeBounds=true to check dimensions
    final BitmapFactory.Options options = new BitmapFactory.Options();
    options.inJustDecodeBounds = true;
    BitmapFactory.decodeResource(res, resId, options);

    // Calculate inSampleSize
    options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);

    // Decode bitmap with inSampleSize set
    options.inJustDecodeBounds = false;
    return BitmapFactory.decodeResource(res, resId, options);
}

Этот метод позволяет легко загружать растровое изображение произвольно большого размера в , ImageViewкоторый отображает 100x100 пикселей , эскиз, как показано в следующем примере кода:

mImageView.setImageBitmap(
    decodeSampledBitmapFromResource(getResources(), R.id.myimage, 100, 100));

Вы можете следить за аналогичный процесс декодирования растровых изображений из других источников, подставляя соответствующий BitmapFactory.decode*метод в случае необходимости.

Ответил 12/04/2012 в 17:31
источник пользователем

голоса
351

Я сделал небольшое усовершенствование кода Федора. Это в основном делает то же самое, но без (на мой взгляд) некрасиво время цикла, и это всегда приводит к власти двух. Престижность Fedor для изготовления оригинального решения, я застрял, пока я не нашел его, а затем я был в состоянии сделать это один :)

 private Bitmap decodeFile(File f){
    Bitmap b = null;

        //Decode image size
    BitmapFactory.Options o = new BitmapFactory.Options();
    o.inJustDecodeBounds = true;

    FileInputStream fis = new FileInputStream(f);
    BitmapFactory.decodeStream(fis, null, o);
    fis.close();

    int scale = 1;
    if (o.outHeight > IMAGE_MAX_SIZE || o.outWidth > IMAGE_MAX_SIZE) {
        scale = (int)Math.pow(2, (int) Math.ceil(Math.log(IMAGE_MAX_SIZE / 
           (double) Math.max(o.outHeight, o.outWidth)) / Math.log(0.5)));
    }

    //Decode with inSampleSize
    BitmapFactory.Options o2 = new BitmapFactory.Options();
    o2.inSampleSize = scale;
    fis = new FileInputStream(f);
    b = BitmapFactory.decodeStream(fis, null, o2);
    fis.close();

    return b;
}
Ответил 23/08/2010 в 16:25
источник пользователем

голоса
220

Я из опыта IOS, и я был разочарован, чтобы обнаружить проблемы с чем-то таким, как основной нагрузки и показывает изображение. В конце концов, все, что с этим вопросом пытается отобразить достаточно размера изображения. Во всяком случае, здесь два изменения, которые фиксированные мою проблему (и сделал мое приложение очень отзывчив).

1) Каждый раз , когда вы делаете BitmapFactory.decodeXYZ(), убедитесь , что пройти в BitmapFactory.Optionsс inPurgeableнабором для true(и предпочтительно inInputShareableтакже установлен true).

2) никогда не использовать Bitmap.createBitmap(width, height, Config.ARGB_8888). Я не имею в виду НИКОГДА! Я никогда не имел , что вещь не поднимать ошибку памяти после нескольких проходов. Никакое количество recycle(), System.gc()независимо не помогло. Он всегда поднял исключение. Один другой способ , который на самом деле работает, чтобы иметь фиктивный образ в вашем вводимом коэффициенте (или другое растровое изображение , которые вы декодируетесь с помощью шаг-выше), Rescale , что все , что вы хотите, а затем манипулировать результат Bitmap (например, передавая его на холст для удовольствия). Итак, что вы должны использовать вместо этого: Bitmap.createScaledBitmap(srcBitmap, width, height, false). Если по какой - либо причине вы должны использовать грубую силу создать метод, то по крайней мере пройти Config.ARGB_4444.

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

Ответил 15/12/2011 в 23:52
источник пользователем

голоса
84

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

Решение : Переместите изображения в папку «активы» и использовать следующую функцию для получения BitmapDrawable:

public static Drawable getAssetImage(Context context, String filename) throws IOException {
    AssetManager assets = context.getResources().getAssets();
    InputStream buffer = new BufferedInputStream((assets.open("drawable/" + filename + ".png")));
    Bitmap bitmap = BitmapFactory.decodeStream(buffer);
    return new BitmapDrawable(context.getResources(), bitmap);
}
Ответил 24/05/2011 в 21:17
источник пользователем

голоса
69

Я имел эту же проблему и решить ее, избегая функцию BitmapFactory.decodeStream или decodeFile и вместо этого использовал BitmapFactory.decodeFileDescriptor

decodeFileDescriptor Похоже, он вызывает различные собственные методы, чем decodeStream / decodeFile.

В любом случае, что сработало было это (обратите внимание , что я добавил некоторые варианты , как некоторые из них выше, но это не то , что сделал разницу Принципиальное значение имеет вызов. BitmapFactory.decodeFileDescriptor вместо decodeStream или decodeFile ):

private void showImage(String path)   {
    Log.i("showImage","loading:"+path);
    BitmapFactory.Options bfOptions=new BitmapFactory.Options();
    bfOptions.inDither=false;                     //Disable Dithering mode
    bfOptions.inPurgeable=true;                   //Tell to gc that whether it needs free memory, the Bitmap can be cleared
    bfOptions.inInputShareable=true;              //Which kind of reference will be used to recover the Bitmap data after being clear, when it will be used in the future
    bfOptions.inTempStorage=new byte[32 * 1024]; 


    File file=new File(path);
    FileInputStream fs=null;
    try {
        fs = new FileInputStream(file);
    } catch (FileNotFoundException e) {
        //TODO do something intelligent
        e.printStackTrace();
    }

    try {
        if(fs!=null) bm=BitmapFactory.decodeFileDescriptor(fs.getFD(), null, bfOptions);
    } catch (IOException e) {
        //TODO do something intelligent
        e.printStackTrace();
    } finally{ 
        if(fs!=null) {
            try {
                fs.close();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }
    //bm=BitmapFactory.decodeFile(path, bfOptions); This one causes error: java.lang.OutOfMemoryError: bitmap size exceeds VM budget

    im.setImageBitmap(bm);
    //bm.recycle();
    bm=null;



}

Я думаю , что есть проблема с нативной функцией , используемой в decodeStream / decodeFile. Я подтвердил , что другой родной метод вызывается при использовании decodeFileDescriptor. Кроме того, что я прочитал это « что изображения (Растровый) не выделяются стандартным способом Java , но с помощью нативных вызовов; ассигнования осуществляются за пределами виртуальной кучи, но подсчитываются против него! »

Ответил 19/08/2011 в 02:55
источник пользователем

голоса
64

Я думаю , что лучший способ избежать OutOfMemoryErrorк лицу и понять его.

Я сделал приложение намеренно вызывать OutOfMemoryErrorи контролировать использование памяти.

После того, как я сделал много экспериментов с этим приложением, я получил следующие выводы:

Я буду говорить о SDK версии до Honey Comb в первую очередь.

  1. Bitmap хранится в родной куче, но он будет получать мусор автоматически, вызывая рециркуляцию () излишне.

  2. Если {VM размер кучи} + {выделено родная память кучи}> = {VM предельного размера кучи для устройства}, и вы пытаетесь создать изображение, ОЫЙ будет отброшены.

    ВНИМАНИЕ: VM КУЧА SIZE отсчитывается вместо VM распределяемой памяти.

  3. размер VM Heap никогда не термоусадочной после выращены, даже если выделенная память VM усаживается.

  4. Таким образом, вы должны держать VM памяти пик как можно меньше, чтобы сохранить VM Heap Size расти слишком большой, чтобы сохранить доступную память для Bitmaps.

  5. Вручную называть System.gc () не имеет смысла, то система будет называть его первым, прежде чем пытаться расти размер кучи.

  6. Родной размер кучи никогда не будет сжиматься тоже, но это не рассчитывал на ООМ, поэтому нет необходимости беспокоиться об этом.

Тогда давайте поговорим о SDK начинается от Honey Comb.

  1. Bitmap хранится в VM куче, Native память не учитывается для ООГО.

  2. Условие ООМ намного проще: {VM размер кучи}> = {VM предельного размера кучи для устройства}.

  3. Таким образом, у Вас есть больше доступная память для создания растрового изображения с таким же предельным размером кучи, ООМ, менее вероятно, будет выброшено.

Вот некоторые из моих наблюдений о Garbage Collection и утечке памяти.

Вы можете увидеть это сами в App. Если активность выполнил AsyncTask, все еще работает после того, как активность была уничтожена, активность будет не получить мусор до конца AsyncTask.

Это происходит потому, что AsyncTask является экземпляром анонимного внутреннего класса, он содержит ссылку деятельности.

Вызов AsyncTask.cancel (истинный) не остановит выполнение, если задача блокируется в операции ввода-вывода в фоновом потоке.

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

Если вы запланировали повторяющуюся или замедленную задачу, например таймер, и вы не вызываете отмены () и продувка () в OnPause (), память будет утечка.

Ответил 01/12/2012 в 04:50
источник пользователем

голоса
58

Я видел много вопросов по поводу исключения OOM и кэширования в последнее время. Руководство разработчика имеет очень хорошую статью по этому поводу , но некоторые , как правило, не в состоянии по реализации его соответствующим образом.

Из-за этого я написал пример приложения, которое демонстрирует кэширование в Android среде. Эта реализация еще не получила в OOM.

Посмотрите в конце этого ответа на ссылку к исходному коду.

Требования:

  • Android API 2.1 или выше (я просто не мог управлять, чтобы получить доступную память для приложения в API 1.6 - это единственный фрагмент кода, который не работает в API 1.6)
  • пакет Android поддержки

Скриншот

Особенности:

  • Сохраняет кэш , если есть изменение ориентации , используя синглтон
  • Используйте одну восьмую присвоенной памяти приложения в кэш - память (изменить , если вы хотите)
  • Большие растровые изображения получает масштабируется (вы можете определить максимальное количество пикселей , которые вы хотите разрешить)
  • Органы управления , что есть подключение к интернету перед загрузкой растровых изображений
  • Гарантирует , что вы только инстанцирование одну задачи для каждой строки
  • Если вы отбросив в ListViewсторону, он просто не будет загружать растровые изображения между

Это не включает в себя:

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

Образец кода:

Изображения, которые загружаются образы (75x75) из Flickr. Тем не менее, положить все изображение URLs вы хотите быть обработаны, и приложение будет масштабировать его вниз , если он превышает максимально допустимую. При таком применении URLs просто в Stringмассиве.

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

Критический материал Cache.java ( в loadBitmap()метод является наиболее важным):

public Cache(int size, int maxWidth, int maxHeight) {
    // Into the constructor you add the maximum pixels
    // that you want to allow in order to not scale images.
    mMaxWidth = maxWidth;
    mMaxHeight = maxHeight;

    mBitmapCache = new LruCache<String, Bitmap>(size) {
        protected int sizeOf(String key, Bitmap b) {
            // Assuming that one pixel contains four bytes.
            return b.getHeight() * b.getWidth() * 4;
        }
    };

    mCurrentTasks = new ArrayList<String>();    
}

/**
 * Gets a bitmap from cache. 
 * If it is not in cache, this method will:
 * 
 * 1: check if the bitmap url is currently being processed in the
 * BitmapLoaderTask and cancel if it is already in a task (a control to see
 * if it's inside the currentTasks list).
 * 
 * 2: check if an internet connection is available and continue if so.
 * 
 * 3: download the bitmap, scale the bitmap if necessary and put it into
 * the memory cache.
 * 
 * 4: Remove the bitmap url from the currentTasks list.
 * 
 * 5: Notify the ListAdapter.
 * 
 * @param mainActivity - Reference to activity object, in order to
 * call notifyDataSetChanged() on the ListAdapter.
 * @param imageKey - The bitmap url (will be the key).
 * @param imageView - The ImageView that should get an
 * available bitmap or a placeholder image.
 * @param isScrolling - If set to true, we skip executing more tasks since
 * the user probably has flinged away the view.
 */
public void loadBitmap(MainActivity mainActivity, 
        String imageKey, ImageView imageView,
        boolean isScrolling) {
    final Bitmap bitmap = getBitmapFromCache(imageKey); 

    if (bitmap != null) {
        imageView.setImageBitmap(bitmap);
    } else {
        imageView.setImageResource(R.drawable.ic_launcher);
        if (!isScrolling && !mCurrentTasks.contains(imageKey) && 
                mainActivity.internetIsAvailable()) {
            BitmapLoaderTask task = new BitmapLoaderTask(imageKey,
                    mainActivity.getAdapter());
            task.execute();
        }
    } 
}

Вам не нужно редактировать что-либо в файле Cache.java, если вы не хотите, чтобы реализовать кэширование диска.

критический материал MainActivity.java в:

public void onScrollStateChanged(AbsListView view, int scrollState) {
    if (view.getId() == android.R.id.list) {
        // Set scrolling to true only if the user has flinged the       
        // ListView away, hence we skip downloading a series
        // of unnecessary bitmaps that the user probably
        // just want to skip anyways. If we scroll slowly it
        // will still download bitmaps - that means
        // that the application won't wait for the user
        // to lift its finger off the screen in order to
        // download.
        if (scrollState == SCROLL_STATE_FLING) {
            mIsScrolling = true;
        } else {
            mIsScrolling = false;
            mListAdapter.notifyDataSetChanged();
        }
    } 
}

// Inside ListAdapter...
@Override
public View getView(final int position, View convertView, ViewGroup parent) {           
    View row = convertView;
    final ViewHolder holder;

    if (row == null) {
        LayoutInflater inflater = getLayoutInflater();
        row = inflater.inflate(R.layout.main_listview_row, parent, false);  
        holder = new ViewHolder(row);
        row.setTag(holder);
    } else {
        holder = (ViewHolder) row.getTag();
    }   

    final Row rowObject = getItem(position);

    // Look at the loadBitmap() method description...
    holder.mTextView.setText(rowObject.mText);      
    mCache.loadBitmap(MainActivity.this,
            rowObject.mBitmapUrl, holder.mImageView,
            mIsScrolling);  

    return row;
}

getView()вызывается очень часто. Это обычно не очень хорошая идея , чтобы загружать изображения там , если мы не реализовали проверку , что обеспечит нам , что мы не будем начинать бесконечное количество нитей в ряд. Cache.java проверяет ли rowObject.mBitmapUrlуже в задаче , и если она есть, она не запустится другой. Таким образом, мы , скорее всего , не превышая ограничение очереди работ из AsyncTaskбассейна.

Скачать:

Вы можете загрузить исходный код из https://www.dropbox.com/s/pvr9zyl811tfeem/ListViewImageCache.zip .


Последние слова:

Я испытал это в течение нескольких недель, я не получил ни одного исключения ООМ еще. Я испытал это на эмуляторе, на моем Nexus One и Nexus S. моего я испытал URL изображений, которые содержат изображения, которые были в качестве HD. Единственным узким местом является то, что она занимает больше времени, чтобы загрузить.

Существует только один возможный сценарий, где я могу себе представить, что ООМ будет появляться, и что если мы загружаем много, действительно больших изображений, и, прежде чем они масштабируются и поместить в кэш, будет одновременно занимать больше памяти и вызвать OOM. Но это даже не идеальная ситуация, в любом случае, и это, скорее всего, не удастся решить в более осуществимым способом.

Сообщения об ошибках в комментариях! :-)

Ответил 24/08/2012 в 11:32
источник пользователем

голоса
36

Я сделал следующее принимать изображение и изменить его на лету. Надеюсь это поможет

Bitmap bm;
bm = Bitmap.createScaledBitmap(BitmapFactory.decodeFile(filepath), 100, 100, true);
mPicture = new ImageView(context);
mPicture.setImageBitmap(bm);    
Ответил 16/02/2009 в 07:23
источник пользователем

голоса
31

Кажется , что это очень долго работает проблема, с большим количеством различных объяснений. Я взял совет из двух наиболее распространенных представленных ответов здесь, но ни один из них решил мои проблемы ВМ утверждая , что она не может позволить себе байты для выполнения декодирования части процесса. После некоторого копания я узнал , что реальная проблема здесь процесс декодирования забирая из ОТЕЧЕСТВЕННОЙ кучи.

Смотрите здесь: BitmapFactory ООМ сводит меня с ума

Это привело меня к другой дискуссионной теме , где я нашел еще пару решений этой проблемы. Один заключается в вызове System.gc();вручную после того, как отображается ваше изображение. Но что на самом деле делает ваше приложение использует больше памяти, в целях сокращения родной кучи. Лучшее решение от выпуска 2.0 (Donut) заключается в использовании BitmapFactory опции «inPurgeable». Так что я просто добавил o2.inPurgeable=true;только после o2.inSampleSize=scale;.

Еще на эту тему здесь: Является ли предел памяти кучи только 6М?

Теперь, сказав все это, я полный балбес с Java и Android тоже. Так что если вы думаете, что это ужасный способ решить эту проблему, вы, вероятно, правы. ;-) Но это творило чудеса для меня, и я нашел, что это невозможно запустить виртуальную машину из кучи кэша в настоящее время. Единственный недостаток, который я могу найти то, что вы громить ваши кэшированные нарисованное изображение. А это значит, если вы идете обратно в этот образ, вы перерисовки его каждый раз. В случае, как работает мое приложение, что это на самом деле не является проблемой. Ваш пробег может варьироваться.

Ответил 19/05/2011 в 17:49
источник пользователем

голоса
29

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

 <application
         android:largeHeap="true"
Ответил 19/05/2015 в 05:51
источник пользователем

голоса
26

Используйте bitmap.recycle();Это помогает без любого вопроса качества изображения.

Ответил 07/11/2010 в 12:08
источник пользователем

голоса
24

Я решил один и тот же вопрос в следующим образом.

Bitmap b = null;
Drawable d;
ImageView i = new ImageView(mContext);
try {
    b = Bitmap.createBitmap(320,424,Bitmap.Config.RGB_565);
    b.eraseColor(0xFFFFFFFF);
    Rect r = new Rect(0, 0,320 , 424);
    Canvas c = new Canvas(b);
    Paint p = new Paint();
    p.setColor(0xFFC0C0C0);
    c.drawRect(r, p);
    d = mContext.getResources().getDrawable(mImageIds[position]);
    d.setBounds(r);
    d.draw(c);

    /*   
        BitmapFactory.Options o2 = new BitmapFactory.Options();
        o2.inTempStorage = new byte[128*1024];
        b = BitmapFactory.decodeStream(mContext.getResources().openRawResource(mImageIds[position]), null, o2);
        o2.inSampleSize=16;
        o2.inPurgeable = true;
    */
} catch (Exception e) {

}
i.setImageBitmap(b);
Ответил 04/06/2011 в 10:44
источник пользователем

голоса
24

У меня есть гораздо более эффективное решение, которое не нуждается в масштабировании любого рода. Просто расшифровать ваш растровый только один раз, а затем кэширует его в карте от его имени. Затем просто получить растровый от имени и установить его в ImageView. Там нет ничего, что должно быть сделано.

Это будет работать, так как фактические двоичные данные декодированного растрового изображения не сохраняются в Dalvik VM кучи. Она хранится снаружи. Таким образом, каждый раз, когда вы расшифровать битовую карту, она выделяет память за пределами VM кучи, которая никогда не утилизирована GC

Для того, чтобы помочь вам лучше понять это, представьте, что вы сохранили ур изображение в вытяжке папке. Вы просто получить изображение, делая GetResources (). GetDrwable (R.drawable.). Это не будет декодировать ваш каждый раз изображения, но повторно использовать уже декодируется экземпляр каждый раз, когда вы это называете. Таким образом, в сущности, это кэшируется.

Теперь, так как ваше изображение находится в файле где-то (или даже может приходить с внешнего сервера), это ВАША ответственность кэшировать экземпляр декодированного растровый для повторного использования любого где это необходимо.

Надеюсь это поможет.

Ответил 02/03/2011 в 19:17
источник пользователем

голоса
23

Это работает для меня!

public Bitmap readAssetsBitmap(String filename) throws IOException {
    try {
        BitmapFactory.Options options = new BitmapFactory.Options(); 
        options.inPurgeable = true;
        Bitmap bitmap = BitmapFactory.decodeStream(assets.open(filename), null, options);
        if(bitmap == null) {
            throw new IOException("File cannot be opened: It's value is null");
        } else {
            return bitmap;
        }
    } catch (IOException e) {
        throw new IOException("File cannot be opened: " + e.getMessage());
    }
}
Ответил 09/06/2012 в 21:33
источник пользователем

голоса
23

Есть две проблемы ....

  • Bitmap памяти не в куче VM, а в родной куче - см BitmapFactory ООМ сводит меня с ума
  • Сбор мусора для родной кучи ленивее кучи VM - так что вы должны быть довольно агрессивными о выполнении bitmap.recycle и растрового = нуль каждый раз, когда вы идете через OnPause или OnDestroy это деятельности по
Ответил 12/05/2011 в 05:40
источник пользователем

голоса
19

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

Вот мой BitmapHelper класс , который OutOfMemoryError доказательство :-)

import java.io.File;
import java.io.FileInputStream;

import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;

public class BitmapHelper
{

    //decodes image and scales it to reduce memory consumption
    public static Bitmap decodeFile(File bitmapFile, int requiredWidth, int requiredHeight, boolean quickAndDirty)
    {
        try
        {
            //Decode image size
            BitmapFactory.Options bitmapSizeOptions = new BitmapFactory.Options();
            bitmapSizeOptions.inJustDecodeBounds = true;
            BitmapFactory.decodeStream(new FileInputStream(bitmapFile), null, bitmapSizeOptions);

            // load image using inSampleSize adapted to required image size
            BitmapFactory.Options bitmapDecodeOptions = new BitmapFactory.Options();
            bitmapDecodeOptions.inTempStorage = new byte[16 * 1024];
            bitmapDecodeOptions.inSampleSize = computeInSampleSize(bitmapSizeOptions, requiredWidth, requiredHeight, false);
            bitmapDecodeOptions.inPurgeable = true;
            bitmapDecodeOptions.inDither = !quickAndDirty;
            bitmapDecodeOptions.inPreferredConfig = quickAndDirty ? Bitmap.Config.RGB_565 : Bitmap.Config.ARGB_8888;

            Bitmap decodedBitmap = BitmapFactory.decodeStream(new FileInputStream(bitmapFile), null, bitmapDecodeOptions);

            // scale bitmap to mathc required size (and keep aspect ratio)

            float srcWidth = (float) bitmapDecodeOptions.outWidth;
            float srcHeight = (float) bitmapDecodeOptions.outHeight;

            float dstWidth = (float) requiredWidth;
            float dstHeight = (float) requiredHeight;

            float srcAspectRatio = srcWidth / srcHeight;
            float dstAspectRatio = dstWidth / dstHeight;

            // recycleDecodedBitmap is used to know if we must recycle intermediary 'decodedBitmap'
            // (DO NOT recycle it right away: wait for end of bitmap manipulation process to avoid
            // java.lang.RuntimeException: Canvas: trying to use a recycled bitmap android.graphics.Bitmap@416ee7d8
            // I do not excatly understand why, but this way it's OK

            boolean recycleDecodedBitmap = false;

            Bitmap scaledBitmap = decodedBitmap;
            if (srcAspectRatio < dstAspectRatio)
            {
                scaledBitmap = getScaledBitmap(decodedBitmap, (int) dstWidth, (int) (srcHeight * (dstWidth / srcWidth)));
                // will recycle recycleDecodedBitmap
                recycleDecodedBitmap = true;
            }
            else if (srcAspectRatio > dstAspectRatio)
            {
                scaledBitmap = getScaledBitmap(decodedBitmap, (int) (srcWidth * (dstHeight / srcHeight)), (int) dstHeight);
                recycleDecodedBitmap = true;
            }

            // crop image to match required image size

            int scaledBitmapWidth = scaledBitmap.getWidth();
            int scaledBitmapHeight = scaledBitmap.getHeight();

            Bitmap croppedBitmap = scaledBitmap;

            if (scaledBitmapWidth > requiredWidth)
            {
                int xOffset = (scaledBitmapWidth - requiredWidth) / 2;
                croppedBitmap = Bitmap.createBitmap(scaledBitmap, xOffset, 0, requiredWidth, requiredHeight);
                scaledBitmap.recycle();
            }
            else if (scaledBitmapHeight > requiredHeight)
            {
                int yOffset = (scaledBitmapHeight - requiredHeight) / 2;
                croppedBitmap = Bitmap.createBitmap(scaledBitmap, 0, yOffset, requiredWidth, requiredHeight);
                scaledBitmap.recycle();
            }

            if (recycleDecodedBitmap)
            {
                decodedBitmap.recycle();
            }
            decodedBitmap = null;

            scaledBitmap = null;
            return croppedBitmap;
        }
        catch (Exception ex)
        {
            ex.printStackTrace();
        }
        return null;
    }

    /**
     * compute powerOf2 or exact scale to be used as {@link BitmapFactory.Options#inSampleSize} value (for subSampling)
     * 
     * @param requiredWidth
     * @param requiredHeight
     * @param powerOf2
     *            weither we want a power of 2 sclae or not
     * @return
     */
    public static int computeInSampleSize(BitmapFactory.Options options, int dstWidth, int dstHeight, boolean powerOf2)
    {
        int inSampleSize = 1;

        // Raw height and width of image
        final int srcHeight = options.outHeight;
        final int srcWidth = options.outWidth;

        if (powerOf2)
        {
            //Find the correct scale value. It should be the power of 2.

            int tmpWidth = srcWidth, tmpHeight = srcHeight;
            while (true)
            {
                if (tmpWidth / 2 < dstWidth || tmpHeight / 2 < dstHeight)
                    break;
                tmpWidth /= 2;
                tmpHeight /= 2;
                inSampleSize *= 2;
            }
        }
        else
        {
            // Calculate ratios of height and width to requested height and width
            final int heightRatio = Math.round((float) srcHeight / (float) dstHeight);
            final int widthRatio = Math.round((float) srcWidth / (float) dstWidth);

            // Choose the smallest ratio as inSampleSize value, this will guarantee
            // a final image with both dimensions larger than or equal to the
            // requested height and width.
            inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;
        }

        return inSampleSize;
    }

    public static Bitmap drawableToBitmap(Drawable drawable)
    {
        if (drawable instanceof BitmapDrawable)
        {
            return ((BitmapDrawable) drawable).getBitmap();
        }

        Bitmap bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), Config.ARGB_8888);
        Canvas canvas = new Canvas(bitmap);
        drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
        drawable.draw(canvas);

        return bitmap;
    }

    public static Bitmap getScaledBitmap(Bitmap bitmap, int newWidth, int newHeight)
    {
        int width = bitmap.getWidth();
        int height = bitmap.getHeight();
        float scaleWidth = ((float) newWidth) / width;
        float scaleHeight = ((float) newHeight) / height;

        // CREATE A MATRIX FOR THE MANIPULATION
        Matrix matrix = new Matrix();
        // RESIZE THE BIT MAP
        matrix.postScale(scaleWidth, scaleHeight);

        // RECREATE THE NEW BITMAP
        Bitmap resizedBitmap = Bitmap.createBitmap(bitmap, 0, 0, width, height, matrix, false);
        return resizedBitmap;
    }

}
Ответил 03/02/2013 в 16:03
источник пользователем

голоса
18

Это работает для меня.

Bitmap myBitmap;

BitmapFactory.Options options = new BitmapFactory.Options(); 
options.InPurgeable = true;
options.OutHeight = 50;
options.OutWidth = 50;
options.InSampleSize = 4;

File imgFile = new File(filepath);
myBitmap = BitmapFactory.DecodeFile(imgFile.AbsolutePath, options);

и это на C # monodroid. Вы можете легко изменить путь к изображению. то, что важно здесь варианты, которые будут установлены.

Ответил 02/10/2012 в 11:33
источник пользователем

голоса
18

Ни один из ответов выше, не работают для меня, но я придумал ужасно некрасивыми обходной, что решить эту проблему. Я добавил очень маленький, 1x1 пикселя изображения для моего проекта в качестве ресурса, и загрузить его в мой ImageView перед вызовом в процессе сборки мусора. Я думаю, что это может быть, что ImageView не отпуская Bitmap, поэтому GC никогда не поднял его. Это некрасиво, но это, кажется, работает на данный момент.

if (bitmap != null)
{
  bitmap.recycle();
  bitmap = null;
}
if (imageView != null)
{
  imageView.setImageResource(R.drawable.tiny); // This is my 1x1 png.
}
System.gc();

imageView.setImageBitmap(...); // Do whatever you need to do to load the image you want.
Ответил 07/12/2011 в 13:32
источник пользователем

голоса
14

В одном из моего приложения мне нужно сделать снимок , либо с Camera/Gallery. Если пользователь нажимает изображение из камеры (может быть 2MP, 5MP или 8MP), размер изображения изменяется от kBS до MBS. Если размер изображения меньше (или до 1-2MB) выше код работает нормально , но если у меня есть изображение размером выше 4MB или 5MB затем OOMприходит в кадре :(

Затем я работал, чтобы решить эту проблему, и, наконец, я сделал ниже усовершенствование Федора (всей кредитный Федор для создания такого хорошим раствора) кода :)

private Bitmap decodeFile(String fPath) {
    // Decode image size
    BitmapFactory.Options opts = new BitmapFactory.Options();
    /*
     * If set to true, the decoder will return null (no bitmap), but the
     * out... fields will still be set, allowing the caller to query the
     * bitmap without having to allocate the memory for its pixels.
     */
    opts.inJustDecodeBounds = true;
    opts.inDither = false; // Disable Dithering mode
    opts.inPurgeable = true; // Tell to gc that whether it needs free
                                // memory, the Bitmap can be cleared
    opts.inInputShareable = true; // Which kind of reference will be used to
                                    // recover the Bitmap data after being
                                    // clear, when it will be used in the
                                    // future

    BitmapFactory.decodeFile(fPath, opts);

    // The new size we want to scale to
    final int REQUIRED_SIZE = 70;

    // Find the correct scale value. 
    int scale = 1;

    if (opts.outHeight > REQUIRED_SIZE || opts.outWidth > REQUIRED_SIZE) {

        // Calculate ratios of height and width to requested height and width
        final int heightRatio = Math.round((float) opts.outHeight
                / (float) REQUIRED_SIZE);
        final int widthRatio = Math.round((float) opts.outWidth
                / (float) REQUIRED_SIZE);

        // Choose the smallest ratio as inSampleSize value, this will guarantee
        // a final image with both dimensions larger than or equal to the
        // requested height and width.
        scale = heightRatio < widthRatio ? heightRatio : widthRatio;//
    }

    // Decode bitmap with inSampleSize set
    opts.inJustDecodeBounds = false;

    opts.inSampleSize = scale;

    Bitmap bm = BitmapFactory.decodeFile(fPath, opts).copy(
            Bitmap.Config.RGB_565, false);

    return bm;

}

Я надеюсь, что это поможет приятелям перед той же проблемой!

более пожалуйста , обратитесь в этом

Ответил 06/02/2013 в 15:53
источник пользователем

голоса
14

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

package com.emil;

import java.io.IOException;
import java.io.InputStream;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;

/**
 * A class to load and process images of various sizes from input streams and file paths.
 * 
 * @author Emil http://stackoverflow.com/users/220710/emil
 *
 */
public class ImageProcessing {

    public static Bitmap getBitmap(InputStream stream, int sampleSize, Bitmap.Config bitmapConfig) throws IOException{
        BitmapFactory.Options options=ImageProcessing.getOptionsForSampling(sampleSize, bitmapConfig);
        Bitmap bm = BitmapFactory.decodeStream(stream,null,options);
        if(ImageProcessing.checkDecode(options)){
            return bm;
        }else{
            throw new IOException("Image decoding failed, using stream.");
        }
    }

    public static Bitmap getBitmap(String imgPath, int sampleSize, Bitmap.Config bitmapConfig) throws IOException{
        BitmapFactory.Options options=ImageProcessing.getOptionsForSampling(sampleSize, bitmapConfig);
        Bitmap bm = BitmapFactory.decodeFile(imgPath,options);
        if(ImageProcessing.checkDecode(options)){
            return bm;
        }else{
            throw new IOException("Image decoding failed, using file path.");
        }
    }

    public static Dimensions getDimensions(InputStream stream) throws IOException{
        BitmapFactory.Options options=ImageProcessing.getOptionsForDimensions();
        BitmapFactory.decodeStream(stream,null,options);
        if(ImageProcessing.checkDecode(options)){
            return new ImageProcessing.Dimensions(options.outWidth,options.outHeight);
        }else{
            throw new IOException("Image decoding failed, using stream.");
        }
    }

    public static Dimensions getDimensions(String imgPath) throws IOException{
        BitmapFactory.Options options=ImageProcessing.getOptionsForDimensions();
        BitmapFactory.decodeFile(imgPath,options);
        if(ImageProcessing.checkDecode(options)){
            return new ImageProcessing.Dimensions(options.outWidth,options.outHeight);
        }else{
            throw new IOException("Image decoding failed, using file path.");
        }
    }

    private static boolean checkDecode(BitmapFactory.Options options){
        // Did decode work?
        if( options.outWidth<0 || options.outHeight<0 ){
            return false;
        }else{
            return true;
        }
    }

    /**
     * Creates a Bitmap that is of the minimum dimensions necessary
     * @param bm
     * @param min
     * @return
     */
    public static Bitmap createMinimalBitmap(Bitmap bm, ImageProcessing.Minimize min){
        int newWidth, newHeight;
        switch(min.type){
        case WIDTH:
            if(bm.getWidth()>min.minWidth){
                newWidth=min.minWidth;
                newHeight=ImageProcessing.getScaledHeight(newWidth, bm);
            }else{
                // No resize
                newWidth=bm.getWidth();
                newHeight=bm.getHeight();
            }
            break;
        case HEIGHT:
            if(bm.getHeight()>min.minHeight){
                newHeight=min.minHeight;
                newWidth=ImageProcessing.getScaledWidth(newHeight, bm);
            }else{
                // No resize
                newWidth=bm.getWidth();
                newHeight=bm.getHeight();
            }
            break;
        case BOTH: // minimize to the maximum dimension
        case MAX:
            if(bm.getHeight()>bm.getWidth()){
                // Height needs to minimized
                min.minDim=min.minDim!=null ? min.minDim : min.minHeight;
                if(bm.getHeight()>min.minDim){
                    newHeight=min.minDim;
                    newWidth=ImageProcessing.getScaledWidth(newHeight, bm);
                }else{
                    // No resize
                    newWidth=bm.getWidth();
                    newHeight=bm.getHeight();
                }
            }else{
                // Width needs to be minimized
                min.minDim=min.minDim!=null ? min.minDim : min.minWidth;
                if(bm.getWidth()>min.minDim){
                    newWidth=min.minDim;
                    newHeight=ImageProcessing.getScaledHeight(newWidth, bm);
                }else{
                    // No resize
                    newWidth=bm.getWidth();
                    newHeight=bm.getHeight();
                }
            }
            break;
        default:
            // No resize
            newWidth=bm.getWidth();
            newHeight=bm.getHeight();
        }
        return Bitmap.createScaledBitmap(bm, newWidth, newHeight, true);
    }

    public static int getScaledWidth(int height, Bitmap bm){
        return (int)(((double)bm.getWidth()/bm.getHeight())*height);
    }

    public static int getScaledHeight(int width, Bitmap bm){
        return (int)(((double)bm.getHeight()/bm.getWidth())*width);
    }

    /**
     * Get the proper sample size to meet minimization restraints
     * @param dim
     * @param min
     * @param multipleOf2 for fastest processing it is recommended that the sample size be a multiple of 2
     * @return
     */
    public static int getSampleSize(ImageProcessing.Dimensions dim, ImageProcessing.Minimize min, boolean multipleOf2){
        switch(min.type){
        case WIDTH:
            return ImageProcessing.getMaxSampleSize(dim.width, min.minWidth, multipleOf2);
        case HEIGHT:
            return ImageProcessing.getMaxSampleSize(dim.height, min.minHeight, multipleOf2);
        case BOTH:
            int widthMaxSampleSize=ImageProcessing.getMaxSampleSize(dim.width, min.minWidth, multipleOf2);
            int heightMaxSampleSize=ImageProcessing.getMaxSampleSize(dim.height, min.minHeight, multipleOf2);
            // Return the smaller of the two
            if(widthMaxSampleSize<heightMaxSampleSize){
                return widthMaxSampleSize;
            }else{
                return heightMaxSampleSize;
            }
        case MAX:
            // Find the larger dimension and go bases on that
            if(dim.width>dim.height){
                return ImageProcessing.getMaxSampleSize(dim.width, min.minDim, multipleOf2);
            }else{
                return ImageProcessing.getMaxSampleSize(dim.height, min.minDim, multipleOf2);
            }
        }
        return 1;
    }

    public static int getMaxSampleSize(int dim, int min, boolean multipleOf2){
        int add=multipleOf2 ? 2 : 1;
        int size=0;
        while(min<(dim/(size+add))){
            size+=add;
        }
        size = size==0 ? 1 : size;
        return size;        
    }

    public static class Dimensions {
        int width;
        int height;

        public Dimensions(int width, int height) {
            super();
            this.width = width;
            this.height = height;
        }

        @Override
        public String toString() {
            return width+" x "+height;
        }
    }

    public static class Minimize {
        public enum Type {
            WIDTH,HEIGHT,BOTH,MAX
        }
        Integer minWidth;
        Integer minHeight;
        Integer minDim;
        Type type;

        public Minimize(int min, Type type) {
            super();
            this.type = type;
            switch(type){
            case WIDTH:
                this.minWidth=min;
                break;
            case HEIGHT:
                this.minHeight=min;
                break;
            case BOTH:
                this.minWidth=min;
                this.minHeight=min;
                break;
            case MAX:
                this.minDim=min;
                break;
            }
        }

        public Minimize(int minWidth, int minHeight) {
            super();
            this.type=Type.BOTH;
            this.minWidth = minWidth;
            this.minHeight = minHeight;
        }

    }

    /**
     * Estimates size of Bitmap in bytes depending on dimensions and Bitmap.Config
     * @param width
     * @param height
     * @param config
     * @return
     */
    public static long estimateBitmapBytes(int width, int height, Bitmap.Config config){
        long pixels=width*height;
        switch(config){
        case ALPHA_8: // 1 byte per pixel
            return pixels;
        case ARGB_4444: // 2 bytes per pixel, but depreciated
            return pixels*2;
        case ARGB_8888: // 4 bytes per pixel
            return pixels*4;
        case RGB_565: // 2 bytes per pixel
            return pixels*2;
        default:
            return pixels;
        }
    }

    private static BitmapFactory.Options getOptionsForDimensions(){
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds=true;
        return options;
    }

    private static BitmapFactory.Options getOptionsForSampling(int sampleSize, Bitmap.Config bitmapConfig){
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = false;
        options.inDither = false;
        options.inSampleSize = sampleSize;
        options.inScaled = false;
        options.inPreferredConfig = bitmapConfig;
        return options;
    }
}
Ответил 03/11/2012 в 00:41
источник пользователем

голоса
13

Я просто побежал в этот вопрос пару минут назад. Я решил это, делая лучшую работу в управлении моим ListView адаптером. Я думал, что это была проблема с сотнями 50x50px изображений, которые я использовал, оказывается, я пытался надуть мой обычай смотреть каждый раз, когда строка была показана на рисунок. Просто тестирование, чтобы увидеть, если строка была завышена устранил эту ошибку, и я использую сотни растровых изображений. Это на самом деле для Spinner, но базовый адаптер работает все же для ListView. Это простое исправление также значительно улучшить производительность адаптера.

@Override
public View getView(final int position, View convertView, final ViewGroup parent) {

    if(convertView == null){
        LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        convertView = inflater.inflate(R.layout.spinner_row, null);
    }
...
Ответил 24/02/2012 в 20:08
источник пользователем

голоса
12

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

Поэтому, пожалуйста, проверьте в устройстве. Он может работать в устройстве.

Ответил 13/08/2012 в 12:39
источник пользователем

голоса
12

Я провел весь день тестирования этих решений и единственное, что работал для меня вышеупомянутые подходы для получения изображения и вручную вызова GC, которую я знаю, не должно быть необходимым, но это единственное, что работает когда я положил мое приложение под сильным нагрузочного тестирования переключения между различными видами деятельности. Мое приложение имеет список уменьшенных изображений в виде списка в (позволяет сказать, что активность А) и при нажатии на одну из этих образов он принимает вас на другой вид деятельности (позволяет сказать, что активность В), которая показывает основное изображение для этого элемента. Когда я переключаться между этими двумя видами деятельностью, я бы в конечном итоге получить ошибку ООЙ и приложение заставит близко.

Когда я хотел бы получить на полпути вниз ListView это будет катастрофа.

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

@Override
public void onDestroy()
{   
    Cleanup();
    super.onDestroy();
}

private void Cleanup()
{    
    bitmap.recycle();
    System.gc();
    Runtime.getRuntime().gc();  
}
Ответил 27/03/2012 в 20:33
источник пользователем

голоса
11

Мой 2 цента: я решил мои ошибки ОЫХ с точечными изображениями по:

а) масштабирование моих изображений с коэффициентом 2

б) с использованием Пикассо библиотек в моем пользовательском адаптере для ListView, с одной вызовом в GetView , как это:Picasso.with(context).load(R.id.myImage).into(R.id.myImageView);

Ответил 14/07/2013 в 10:08
источник пользователем

голоса
10

использовать эти символы для каждого изображения в выберите из SDCARD или drewable для преобразования растрового объекта.

Resources res = getResources();
WindowManager window = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
Display display = window.getDefaultDisplay();
@SuppressWarnings("deprecation")
int width = display.getWidth();
@SuppressWarnings("deprecation")
int height = display.getHeight();
try {
    if (bitmap != null) {
        bitmap.recycle();
        bitmap = null;
        System.gc();
    }
    bitmap = Bitmap.createScaledBitmap(BitmapFactory
        .decodeFile(ImageData_Path.get(img_pos).getPath()),
        width, height, true);
} catch (OutOfMemoryError e) {
    if (bitmap != null) {
        bitmap.recycle();
        bitmap = null;
        System.gc();
    }
    BitmapFactory.Options options = new BitmapFactory.Options();
    options.inPreferredConfig = Config.RGB_565;
    options.inSampleSize = 1;
    options.inPurgeable = true;
    bitmapBitmap.createScaledBitmap(BitmapFactory.decodeFile(ImageData_Path.get(img_pos)
        .getPath().toString(), options), width, height,true);
}
return bitmap;

использовать изображения путь instend из ImageData_Path.get (img_pos) .getPath () .

Ответил 24/01/2014 в 13:57
источник пользователем

голоса
10

Этот код поможет загрузить большое растровое изображение из вытяжки

public class BitmapUtilsTask extends AsyncTask<Object, Void, Bitmap> {

Context context;

public BitmapUtilsTask(Context context) {
    this.context = context;
}

/**
 * Loads a bitmap from the specified url.
 * 
 * @param url The location of the bitmap asset
 * @return The bitmap, or null if it could not be loaded
 * @throws IOException
 * @throws MalformedURLException
 */
public Bitmap getBitmap() throws MalformedURLException, IOException {       

    // Get the source image's dimensions
    int desiredWidth = 1000;
    BitmapFactory.Options options = new BitmapFactory.Options();
    options.inJustDecodeBounds = true;

    BitmapFactory.decodeResource(context.getResources(), R.drawable.green_background , options);

    int srcWidth = options.outWidth;
    int srcHeight = options.outHeight;

    // Only scale if the source is big enough. This code is just trying
    // to fit a image into a certain width.
    if (desiredWidth > srcWidth)
        desiredWidth = srcWidth;

    // Calculate the correct inSampleSize/scale value. This helps reduce
    // memory use. It should be a power of 2
    int inSampleSize = 1;
    while (srcWidth / 2 > desiredWidth) {
        srcWidth /= 2;
        srcHeight /= 2;
        inSampleSize *= 2;
    }
    // Decode with inSampleSize
    options.inJustDecodeBounds = false;
    options.inDither = false;
    options.inSampleSize = inSampleSize;
    options.inScaled = false;
    options.inPreferredConfig = Bitmap.Config.ARGB_8888;
    options.inPurgeable = true;
    Bitmap sampledSrcBitmap;

    sampledSrcBitmap =  BitmapFactory.decodeResource(context.getResources(), R.drawable.green_background , options);

    return sampledSrcBitmap;
}

/**
 * The system calls this to perform work in a worker thread and delivers
 * it the parameters given to AsyncTask.execute()
 */
@Override
protected Bitmap doInBackground(Object... item) {

    try 
    { 
      return getBitmap();
    } catch (MalformedURLException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
    return null;
 }

}

Ответил 31/10/2012 в 13:03
источник пользователем

голоса
9

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

Я вышел с решением, которое работает с моим Samsung Galaxy S3 и несколько других устройств, в том числе менее мощные, с более высоким качеством изображения при использовании более мощного устройства.

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

public static Bitmap decodeFile(File f)
{
    Bitmap b = null;
    try
    {
        // Decode image size
        BitmapFactory.Options o = new BitmapFactory.Options();
        o.inJustDecodeBounds = true;

        FileInputStream fis = new FileInputStream(f);
        try
        {
            BitmapFactory.decodeStream(fis, null, o);
        }
        finally
        {
            fis.close();
        }

        // In Samsung Galaxy S3, typically max memory is 64mb
        // Camera max resolution is 3264 x 2448, times 4 to get Bitmap memory of 30.5mb for one bitmap
        // If we use scale of 2, resolution will be halved, 1632 x 1224 and x 4 to get Bitmap memory of 7.62mb
        // We try use 25% memory which equals to 16mb maximum for one bitmap
        long maxMemory = Runtime.getRuntime().maxMemory();
        int maxMemoryForImage = (int) (maxMemory / 100 * 25);

        // Refer to
        // http://developer.android.com/training/displaying-bitmaps/cache-bitmap.html
        // A full screen GridView filled with images on a device with
        // 800x480 resolution would use around 1.5MB (800*480*4 bytes)
        // When bitmap option's inSampleSize doubled, pixel height and
        // weight both reduce in half
        int scale = 1;
        while ((o.outWidth / scale) * (o.outHeight / scale) * 4 > maxMemoryForImage)
        scale *= 2;

        // Decode with inSampleSize
        BitmapFactory.Options o2 = new BitmapFactory.Options();
        o2.inSampleSize = scale;
        fis = new FileInputStream(f);
        try
        {
            b = BitmapFactory.decodeStream(fis, null, o2);
        }
        finally
        {
            fis.close();
        }
    }
    catch (IOException e)
    {
    }
    return b;
}

Я установил максимальный объем памяти, используемый данным растрового изображения будет 25% от максимальной выделенной памяти, возможно, потребуется изменить это к вашим потребностям и убедитесь, что это растровый очищается и не остаются в памяти, когда вы закончили использовать его. Обычно я использую этот код для выполнения поворота изображения (источник и назначение растрового), так что мое приложению нужно загрузить 2 растровые изображения в памяти одновременно, и 25% дает мне хороший буфер без запуска из памяти при выполнении поворота изображения.

Надеюсь, что это помогает кто-то там ..

Ответил 31/08/2013 в 04:04
источник пользователем

голоса
9

Такое OutofMemoryExceptionне может быть полностью решена путем вызова System.gc()и так далее.

Ссылаясь на цикл активности жизни

Деятельность государство определяется самой ОС при условии использования памяти для каждого процесса и приоритет каждого процесса.

Вы можете рассмотреть размер и разрешение для каждого из растровых изображений, используемых. Я рекомендую, чтобы уменьшить размер ресемплировать более низкое разрешение, относится к конструкции галерей (одна маленькой картинки PNG, и одной оригинальной картине.)

Ответил 08/08/2012 в 05:36
источник пользователем

голоса
8

Вообще андроид размер устройства куча всего 16Мб (зависит от устройства / OS см почтовые вороха Размеры ), если вы загружаете изображения и пересекает размер 16Мб, он выбросит исключения памяти, вместо того , чтобы использовать Bitmap для, загрузки изображения с SD - карты или из ресурсов или даже из сети пытаются с помощью getImageUri , загрузка растровых изображений требуются больше памяти, или вы можете установить растровый обнулить , если ваша работу с этой битовой картой.

Ответил 26/11/2012 в 06:48
источник пользователем

голоса
4

Кажется , изображения , которые вы использовали очень большой в size.so некоторых старых устройств аварий происходит из - за кучи памяти full.In старых устройств (расческой или медовой ICS или любых устройств с низким конца модели) пытаются использовать android:largeHeap="true"в файле манифеста под тег приложения или уменьшить размер битовой карты с помощью кода ниже.

Bitmap bMap;
BitmapFactory.Options options = new BitmapFactory.Options(); 
options.InSampleSize = 8;
bMap= BitmapFactory.DecodeFile(imgFile.AbsolutePath, options);

Вы можете также дать 4 или 12 или 16, чтобы уменьшить размер растрового изображения

Ответил 18/12/2014 в 09:40
источник пользователем

голоса
4
BitmapFactory.Options options = new Options();
options.inSampleSize = 32;
//img = BitmapFactory.decodeFile(imageids[position], options);

Bitmap theImage = BitmapFactory.decodeStream(imageStream,null, options);
Bitmap img=theImage.copy(Bitmap.Config.RGB_565,true);
theImage.recycle();
theImage = null;
System.gc();
//ivlogdp.setImageBitmap(img);
Runtime.getRuntime().gc();
Ответил 24/07/2013 в 13:00
источник пользователем

голоса
4

Я попробовал подход Томаса Vervest, но он возвращает масштаб 1 для изображения размером 2592x1944 при IMAGE_MAX_SIZE 2048.

Эта версия работает для меня на основе всех других замечаний, представленных другими:

private Bitmap decodeFile (File f) {
    Bitmap b = null;
    try {
        // Decode image size
        BitmapFactory.Options o = new BitmapFactory.Options ();
        o.inJustDecodeBounds = true;

        FileInputStream fis = new FileInputStream (f);
        try {
            BitmapFactory.decodeStream (fis, null, o);
        } finally {
            fis.close ();
        }

        int scale = 1;
        for (int size = Math.max (o.outHeight, o.outWidth); 
            (size>>(scale-1)) > IMAGE_MAX_SIZE; ++scale);

        // Decode with inSampleSize
        BitmapFactory.Options o2 = new BitmapFactory.Options ();
        o2.inSampleSize = scale;
        fis = new FileInputStream (f);
        try {
            b = BitmapFactory.decodeStream (fis, null, o2);
        } finally {
            fis.close ();
        }
    } catch (IOException e) {
    }
    return b;
}
Ответил 09/12/2012 в 22:45
источник пользователем

голоса
2

Чтобы исправить OutOfMemory вы должны сделать что-то подобное, пожалуйста, попробуйте этот код

public Bitmap loadBitmap(String URL, BitmapFactory.Options options) {
                Bitmap bitmap = null;
                InputStream in = null;
                options.inSampleSize=4;
                try {
                    in = OpenHttpConnection(URL);
                    Log.e("In====>", in+"");
                    bitmap = BitmapFactory.decodeStream(in, null, options);
                    Log.e("URL====>", bitmap+"");

                    in.close();
                } catch (IOException e1) {
                }
                return bitmap;
            }

а также

try {
                    BitmapFactory.Options bmOptions;
                    bmOptions = new BitmapFactory.Options();
                    bmOptions.inSampleSize = 1;
                    if(studentImage != null){
                        galleryThumbnail= loadBitmap(IMAGE_URL+studentImage, bmOptions);    
                    }

                    galleryThumbnail=getResizedBitmap(galleryThumbnail, imgEditStudentPhoto.getHeight(), imgEditStudentPhoto.getWidth());
                    Log.e("Image_Url==>",IMAGE_URL+studentImage+"");

                } catch (Exception e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
Ответил 21/12/2013 в 12:10
источник пользователем

голоса
2

Привет Пожалуйста , перейдите по ссылке http://developer.android.com/training/displaying-bitmaps/index.html

или просто пытаются получить растровое изображение с заданной функцией

private Bitmap decodeBitmapFile (File f) {
    Bitmap bitmap = null;
    try {
        // Decode image size
        BitmapFactory.Options o = new BitmapFactory.Options ();
        o.inJustDecodeBounds = true;

        FileInputStream fis = new FileInputStream (f);
        try {
            BitmapFactory.decodeStream (fis, null, o);
        } finally {
            fis.close ();
        }

        int scale = 1;
        for (int size = Math.max (o.outHeight, o.outWidth); 
            (size>>(scale-1)) > IMAGE_MAX_SIZE; ++scale);

        // Decode with input-stram SampleSize
        BitmapFactory.Options o2 = new BitmapFactory.Options ();
        o2.inSampleSize = scale;
        fis = new FileInputStream (f);
        try {
            bitmap  = BitmapFactory.decodeStream (fis, null, o2);
        } finally {
            fis.close ();
        }
    } catch (IOException e) {
    }
    return bitmap ;
}
Ответил 05/12/2013 в 11:22
источник пользователем

голоса
2

использовать эту концепцию, это поможет вам, После этого установите imagebitmap на просмотр изображения

public static Bitmap convertBitmap(String path)   {

        Bitmap bitmap=null;
        BitmapFactory.Options bfOptions=new BitmapFactory.Options();
        bfOptions.inDither=false;                     //Disable Dithering mode
        bfOptions.inPurgeable=true;                   //Tell to gc that whether it needs free memory, the Bitmap can be cleared
        bfOptions.inInputShareable=true;              //Which kind of reference will be used to recover the Bitmap data after being clear, when it will be used in the future
        bfOptions.inTempStorage=new byte[32 * 1024]; 


        File file=new File(path);
        FileInputStream fs=null;
        try {
            fs = new FileInputStream(file);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }

        try {
            if(fs!=null)
            {
                bitmap=BitmapFactory.decodeFileDescriptor(fs.getFD(), null, bfOptions);
            }
            } catch (IOException e) {

            e.printStackTrace();
        } finally{ 
            if(fs!=null) {
                try {
                    fs.close();
                } catch (IOException e) {

                    e.printStackTrace();
                }
            }
        }

        return bitmap;
    }

Если вы хотите сделать небольшое изображение из большого изображения с высотой и шириной, как 60 и 60 и прокрутить ListView быстро затем использовать эту концепцию

public static Bitmap decodeSampledBitmapFromPath(String path, int reqWidth,
            int reqHeight) {

        final BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        BitmapFactory.decodeFile(path, options);

        options.inSampleSize = calculateInSampleSize(options, reqWidth,
                reqHeight);

        // Decode bitmap with inSampleSize set
        options.inJustDecodeBounds = false;
        Bitmap bmp = BitmapFactory.decodeFile(path, options);
        return bmp;
        }

    public static int calculateInSampleSize(BitmapFactory.Options options,
            int reqWidth, int reqHeight) {

        final int height = options.outHeight;
        final int width = options.outWidth;
        int inSampleSize = 1;

        if (height > reqHeight || width > reqWidth) {
            if (width > height) {
                inSampleSize = Math.round((float) height / (float) reqHeight);
            } else {
                inSampleSize = Math.round((float) width / (float) reqWidth);
             }
         }
         return inSampleSize;
        }

Я надеюсь, что это поможет вам много.

Вы можете принять помощь от разработчика сайта Здесь

Ответил 29/08/2013 в 07:34
источник пользователем

голоса
1

Добавьте следующие строки в файл manifest.xml:

<application

    android:hardwareAccelerated="false"
    android:largeHeap="true"

    <activity>
    </activity>

</application>
Ответил 01/11/2018 в 06:02
источник пользователем

голоса
0

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

     Glide.with(this).load(yourImageResource).into(imageview);

Вы можете получить здесь хранилище: https://github.com/bumptech/glide

Ответил 15/12/2017 в 18:38
источник пользователем

голоса
0

Я использовал Decode File Descriptor, который работал для меня:

 FileInputStream  fileInputStream = null;
        try {
            fileInputStream  = new FileInputStream(file);
             FileDescriptor fd = fileInputStream.getFD();
            Bitmap imageBitmap = decodeSampledBitmapFromDescriptor(fd , 612,
                    816);
            imageView.setImageBitmap(imageBitmap);
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            if(fileInputStream != null){
                try {
                    fileInputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

Код для декодирования сэмпла Bitmap From File Descriptor:

 /**
     * Decode and sample down a bitmap from a file input stream to the requested width and height.
     *
     * @param fileDescriptor The file descriptor to read from
     * @param reqWidth       The requested width of the resulting bitmap
     * @param reqHeight      The requested height of the resulting bitmap
     * @return A bitmap sampled down from the original with the same aspect ratio and dimensions
     * that are equal to or greater than the requested width and height
     */
    public static Bitmap decodeSampledBitmapFromDescriptor(
            FileDescriptor fileDescriptor, int reqWidth, int reqHeight) {

        // First decode with inJustDecodeBounds=true to check dimensions
        final BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        BitmapFactory.decodeFileDescriptor(fileDescriptor, null, options);

        // Calculate inSampleSize
        options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);

        // Decode bitmap with inSampleSize set
        options.inJustDecodeBounds = false;
        return BitmapFactory.decodeFileDescriptor(fileDescriptor, null, options);
    }

    /**
     * Calculate an inSampleSize for use in a {@link android.graphics.BitmapFactory.Options} object when decoding
     * bitmaps using the decode* methods from {@link android.graphics.BitmapFactory}. This implementation calculates
     * the closest inSampleSize that will result in the final decoded bitmap having a width and
     * height equal to or larger than the requested width and height. This implementation does not
     * ensure a power of 2 is returned for inSampleSize which can be faster when decoding but
     * results in a larger bitmap which isn't as useful for caching purposes.
     *
     * @param options   An options object with out* params already populated (run through a decode*
     *                  method with inJustDecodeBounds==true
     * @param reqWidth  The requested width of the resulting bitmap
     * @param reqHeight The requested height of the resulting bitmap
     * @return The value to be used for inSampleSize
     */
    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) {

            // Calculate ratios of height and width to requested height and width
            final int heightRatio = Math.round((float) height / (float) reqHeight);
            final int widthRatio = Math.round((float) width / (float) reqWidth);

            // Choose the smallest ratio as inSampleSize value, this will guarantee a final image
            // with both dimensions larger than or equal to the requested height and width.
            inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;

            // This offers some additional logic in case the image has a strange
            // aspect ratio. For example, a panorama may have a much larger
            // width than height. In these cases the total pixels might still
            // end up being too large to fit comfortably in memory, so we should
            // be more aggressive with sample down the image (=larger inSampleSize).

            final float totalPixels = width * height;

            // Anything more than 2x the requested pixels we'll sample down further
            final float totalReqPixelsCap = reqWidth * reqHeight * 2;

            while (totalPixels / (inSampleSize * inSampleSize) > totalReqPixelsCap) {
                inSampleSize++;
            }
        }
        return inSampleSize;
    }
Ответил 20/07/2017 в 15:46
источник пользователем

голоса
0

Если вы ленивы , как я. Вы можете начать использовать библиотеку Пикассо для загрузки изображений. http://square.github.io/picasso/

Picasso.with(context).load(R.drawable.landing_screen).into(imageView1); Picasso.with(context).load("file:///android_asset/DvpvklR.png").into(imageView2); Picasso.with(context).load(new File(...)).into(imageView3);

Ответил 12/07/2017 в 14:38
источник пользователем

голоса
-8

После установки в растровом изображении, чтобы ImageView, переработать его следующим образом:

bitmap.recycle();
bitmap=null;
Ответил 29/03/2013 в 07:56
источник пользователем

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more