java.lang.OutOfMemoryError — BitmapFactory.decode (strPath)

Я получаю java.lang.OutOfMemoryError всякий раз, когда я вызываю UploadActivity.java

Строка номер 176:

  Bitmap bm = BitmapFactory.decodeFile(strPath);

Просмотреть мой журнал:

12-07 17:57:10.585: E/AndroidRuntime(16708): FATAL EXCEPTION: main
12-07 17:57:10.585: E/AndroidRuntime(16708): java.lang.OutOfMemoryError
12-07 17:57:10.585: E/AndroidRuntime(16708):    at android.graphics.BitmapFactory.nativeDecodeStream(Native Method)
12-07 17:57:10.585: E/AndroidRuntime(16708):    at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:650)
12-07 17:57:10.585: E/AndroidRuntime(16708):    at android.graphics.BitmapFactory.decodeFile(BitmapFactory.java:389)
12-07 17:57:10.585: E/AndroidRuntime(16708):    at android.graphics.BitmapFactory.decodeFile(BitmapFactory.java:449)
12-07 17:57:10.585: E/AndroidRuntime(16708):    at com.example.camera.UploadActivity$ImageAdapter.getView(UploadActivity.java:176)
12-07 17:57:10.585: E/AndroidRuntime(16708):    at android.widget.AbsListView.obtainView(AbsListView.java:2465)
12-07 17:57:10.585: E/AndroidRuntime(16708):    at android.widget.ListView.makeAndAddView(ListView.java:1775)
12-07 17:57:10.585: E/AndroidRuntime(16708):    at android.widget.ListView.fillDown(ListView.java:678)
12-07 17:57:10.585: E/AndroidRuntime(16708):    at android.widget.ListView.fillFromTop(ListView.java:739)
12-07 17:57:10.585: E/AndroidRuntime(16708):    at android.widget.ListView.layoutChildren(ListView.java:1628)
12-07 17:57:10.585: E/AndroidRuntime(16708):    at android.widget.AbsListView.onLayout(AbsListView.java:2300)
12-07 17:57:10.585: E/AndroidRuntime(16708):    at android.view.View.layout(View.java:14063)
12-07 17:57:10.585: E/AndroidRuntime(16708):    at android.view.ViewGroup.layout(ViewGroup.java:4607)
12-07 17:57:10.585: E/AndroidRuntime(16708):    at android.widget.RelativeLayout.onLayout(RelativeLayout.java:948)
12-07 17:57:10.585: E/AndroidRuntime(16708):    at android.view.View.layout(View.java:14063)
12-07 17:57:10.585: E/AndroidRuntime(16708):    at android.view.ViewGroup.layout(ViewGroup.java:4607)
12-07 17:57:10.585: E/AndroidRuntime(16708):    at android.widget.FrameLayout.onLayout(FrameLayout.java:448)
12-07 17:57:10.585: E/AndroidRuntime(16708):    at android.view.View.layout(View.java:14063)
12-07 17:57:10.585: E/AndroidRuntime(16708):    at android.view.ViewGroup.layout(ViewGroup.java:4607)
12-07 17:57:10.585: E/AndroidRuntime(16708):    at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1655)
12-07 17:57:10.585: E/AndroidRuntime(16708):    at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1513)
12-07 17:57:10.585: E/AndroidRuntime(16708):    at android.widget.LinearLayout.onLayout(LinearLayout.java:1426)
12-07 17:57:10.585: E/AndroidRuntime(16708):    at android.view.View.layout(View.java:14063)
12-07 17:57:10.585: E/AndroidRuntime(16708):    at android.view.ViewGroup.layout(ViewGroup.java:4607)
12-07 17:57:10.585: E/AndroidRuntime(16708):    at android.widget.FrameLayout.onLayout(FrameLayout.java:448)
12-07 17:57:10.585: E/AndroidRuntime(16708):    at android.view.View.layout(View.java:14063)
12-07 17:57:10.585: E/AndroidRuntime(16708):    at android.view.ViewGroup.layout(ViewGroup.java:4607)
12-07 17:57:10.585: E/AndroidRuntime(16708):    at android.view.ViewRootImpl.performLayout(ViewRootImpl.java:1996)
12-07 17:57:10.585: E/AndroidRuntime(16708):    at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1817)
12-07 17:57:10.585: E/AndroidRuntime(16708):    at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1114)
12-07 17:57:10.585: E/AndroidRuntime(16708):    at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:4520)
12-07 17:57:10.585: E/AndroidRuntime(16708):    at android.view.Choreographer$CallbackRecord.run(Choreographer.java:725)
12-07 17:57:10.585: E/AndroidRuntime(16708):    at android.view.Choreographer.doCallbacks(Choreographer.java:555)
12-07 17:57:10.585: E/AndroidRuntime(16708):    at android.view.Choreographer.doFrame(Choreographer.java:525)
12-07 17:57:10.585: E/AndroidRuntime(16708):    at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:711)
12-07 17:57:10.585: E/AndroidRuntime(16708):    at android.os.Handler.handleCallback(Handler.java:615)
12-07 17:57:10.585: E/AndroidRuntime(16708):    at android.os.Handler.dispatchMessage(Handler.java:92)
12-07 17:57:10.585: E/AndroidRuntime(16708):    at android.os.Looper.loop(Looper.java:137)
12-07 17:57:10.585: E/AndroidRuntime(16708):    at android.app.ActivityThread.main(ActivityThread.java:4921)
12-07 17:57:10.585: E/AndroidRuntime(16708):    at java.lang.reflect.Method.invokeNative(Native Method)
12-07 17:57:10.585: E/AndroidRuntime(16708):    at java.lang.reflect.Method.invoke(Method.java:511)
12-07 17:57:10.585: E/AndroidRuntime(16708):    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1036)
12-07 17:57:10.585: E/AndroidRuntime(16708):    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:803)
12-07 17:57:10.585: E/AndroidRuntime(16708):    at dalvik.system.NativeStart.main(Native Method)

UploadActivity.java:-

public class ImageAdapter extends BaseAdapter
        {
        private Context context;

        public ImageAdapter(Context c)
        {
        // TODO Auto-generated method stub
        context = c;
        }

        public int getCount() {
        // TODO Auto-generated method stub
        return ImageList.size();
        }

        public Object getItem(int position) {
        // TODO Auto-generated method stub
        return position;
        }

        public long getItemId(int position) {
        // TODO Auto-generated method stub
        return position;
        }

        public View getView(final int position, View convertView, ViewGroup parent) {
        // TODO Auto-generated method stub

        LayoutInflater inflater = (LayoutInflater) context
        .getSystemService(Context.LAYOUT_INFLATER_SERVICE);      

        if (convertView == null) {
        convertView = inflater.inflate(R.layout.list_upload, null);
        }


        // ColImgName
        TextView txtName = (TextView) convertView.findViewById(R.id.ColImgName);
        strPath = ImageList.get(position).toString();

        // Get File Name
        fileName = strPath.substring( strPath.lastIndexOf('/')+1, strPath.length() );
        File file = new File(strPath);
        @SuppressWarnings("unused")
        long length = file.length();
        txtName.setText(fileName);

        // Image Resource
        ImageView imageView = (ImageView) convertView.findViewById(R.id.ColImgPath);
        Bitmap bm = BitmapFactory.decodeFile(strPath);
        imageView.setImageBitmap(bm);


        // ColStatus
        final ImageView txtStatus = (ImageView) convertView.findViewById(R.id.ColStatus);
        txtStatus.setImageResource(R.drawable.bullet_button);

        // progressBar
        final ProgressBar progress = (ProgressBar) convertView.findViewById(R.id.progressBar);
        progress.setVisibility(View.GONE);

        //btnUpload
        final ImageButton btnUpload = (ImageButton) convertView.findViewById(R.id.btnUpload);
        btnUpload.setOnClickListener(new View.OnClickListener() {
        public void onClick(View v) {
        // Upload
        btnUpload.setEnabled(false);

        startUpload(position);
        }
        });

        return convertView;

        }
    } 

person Sun    schedule 07.12.2013    source источник
comment
Вы можете просто заменить параметр Uri на ваше имя файла String. Этот код работает и с BitmapFactory.decodeFile.   -  person zapl    schedule 07.12.2013
comment
@zapl, пожалуйста, покажи мне дорогу   -  person Sun    schedule 07.12.2013
comment
ответ santhosh уже делает примерно это. Попытайся. StackOverflow предполагает, что у вас есть базовые знания о программировании и вы можете сделать это самостоятельно.   -  person zapl    schedule 07.12.2013
comment
@zapl о, извините, в тот раз я не видел ответа Сантоша   -  person Sun    schedule 07.12.2013
comment
если вы можете использовать фрагмент кода, указанный в ответе Сантоша, я считаю, что ваша проблема должна быть решена. Тем не менее здесь developer.android.com/training/displaying-bitmaps/ — это более подробная версия того, как вы должны использовать этот фрагмент кода.   -  person saiful103a    schedule 07.12.2013
comment
какое решение сработало для нас решение 1 или решение 2   -  person Shakeeb Ayaz    schedule 09.12.2013


Ответы (5)


Вам нужно переработать объект Bitmap.

    Bitmap bm = BitmapFactory.decodeFile(strPath);
    imageView.setImageBitmap(bm);

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

    if(bm!=null)
   {
     bm.recycle();
     bm=null;
    }

После этого также, если вы получаете ту же ошибку

Замените приведенный ниже код

    Bitmap bm = BitmapFactory.decodeFile(strPath);
    imageView.setImageBitmap(bm);

с участием

 final BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 8;

Bitmap bm = BitmapFactory.decodeFile(strPath,options);
imageView.setImageBitmap(bm);

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

Дополнительную информацию см. в статье Эффективная загрузка больших растровых изображений.

person Shakeeb Ayaz    schedule 07.12.2013
comment
Я могу ошибаться, но если растровое изображение перерабатывается сразу после setImageBitmap, не должно ли оно вызывать Canvas: попытка использовать ошибку переработанного растрового изображения? - person saiful103a; 07.12.2013
comment
Нет, но я сталкивался с этим раньше, и я пытаюсь понять, как это поможет решить проблему нехватки памяти. Насколько я знаю, после установки растрового изображения, если вы вызываете повторное использование растрового изображения, это не вызовет никаких проблем, если система не сделает представление недействительным. И, как вы предложили, сразу после установки растрового изображения мы должны вызвать bm.recycle();. Теперь, в этом случае, если пользователь прокручивает список/сетку, система аннулирует все в пользовательском интерфейсе, и во время аннулирования система не найдет пиксельные данные изображения. Вот где пользователь получит Canvas: попытка использовать переработанную ошибку растрового изображения? - person saiful103a; 07.12.2013
comment
@ saiful103a вы когда-нибудь регистрировали getView (), чтобы узнать, как работает getview или сколько раз он вызывается при вызове списка ... Еще одна вещь, которую вы не используете. Дизайн держателя представления. Это также может вызвать проблемы с памятью. Вот учебник для держатель вида youtube.com/watch?v=OTEiRiMaQ7M .. Я новичок . Вы старше меня. Если мое слово резкое, пожалуйста, извините меня, я готов исправить себя, если я ошибаюсь. Посмотрев это видео, ваши сомнения относительно моего ответа развеются. - person Shakeeb Ayaz; 07.12.2013
comment
@ShakeebAyaz, ваше решение 2 сработало для меня, и Shakeeb, могу ли я узнать, когда я использую устройство для загрузки изображения, это занимает от 1 до 2 минут ... как ускорить загрузку изображений на сервер - person Sun; 09.12.2013
comment
@ShakeebAyaz Я получаю Canvas: пытаюсь использовать ошибку переработанного растрового изображения ... есть идеи? - person Thomas; 23.03.2014
comment
@ShakeebAyaz Canvas: попытка использовать переработанное растровое изображение - person Thomas; 24.03.2014
comment
@Thomas перед повторным использованием переработанного растрового изображения повторно инициализируйте растровое изображение. - person Shakeeb Ayaz; 24.03.2014
comment
@ShakeebAyaz Даже добавление этого не работает, все равно происходит сбой. - person Narendra Singh; 19.03.2015
comment
@ShakeebAyaz Я попробовал код, рекомендованный Google, по ссылке выше: Большой Растровые изображения Эффективно. Однако иногда я получаю ту же ошибку на реальных устройствах. Я использую изображение размером 1280x1920, 90 кб... Оно слишком велико?! - person fpauer; 14.05.2015

Используйте это в файле манифеста в теге приложения

android:largeHeap="true"
person Milan Pansuriya    schedule 25.08.2015

перед вызовом Bitmap bm=BitmapFactory.decodeFile(strPath);

вызовите это .. Bitmap bm = decodeSampledBitmapFromResource (strPath, reqWidth, reqHeight);

если вы снова получите java.lang.OutOfMemoryError, дайте мне знать

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

public static Bitmap decodeSampledBitmapFromResource(String strPath,int reqWidth, int reqHeight) {

        // First decode with inJustDecodeBounds=true to check dimensions
        final BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        BitmapFactory.decodeFile(strPath, options);
        // Calculate inSampleSize
        options.inSampleSize = calculateInSampleSize(options,reqWidth,
                reqHeight);
        // Decode bitmap with inSampleSize set
        options.inJustDecodeBounds = false;
        return BitmapFactory.decodeFile(strPath, options);;
}
person Santhosh    schedule 07.12.2013
comment
я сделал, как вы написали: но получаю несколько маркеров в этой строке - reqHeight не может быть преобразован в переменную - Синтаксическая ошибка в токене int, удалите этот токен - reqWidth не может быть преобразован в переменную - Синтаксическая ошибка в токене strPath, удалите этот токен - Строка не может быть преобразована в переменную - синтаксическая ошибка в токене int, удалите этот токен в этой строке: Bitmap bm =decodeSampledBitmapFromResource(String strPath,int reqWidth, int reqHeight); - person Sun; 07.12.2013
comment
strPath = абсолютный путь imagePath в SD-карте попробуйте с шириной и высотой 100 x 100 Bitmap bm = decodeSampledBitmapFromResource (strPath, reqWidth, reqHeight) - person Santhosh; 07.12.2013

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

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

Чтобы дать вам более общее представление, вот что происходит:

  • Ширина ImageView * высота = 100dp * 100dp
  • Ширина изображения * высота = 800 пикселей * 800 пикселей.

В этом сценарии ширина-высота нашего изображения составляет 100 * 100, но мы пытаемся установить изображение размером 800 * 800 в качестве фона. И это определенно неэффективный способ, потому что система будет выделять память для изображения размером 800*800 пикселей, тогда как 100*100 подойдет.

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

Вы найдете более подробную версию этого объяснения здесь

person saiful103a    schedule 07.12.2013

У меня такая же проблема. Я включил все вышеперечисленные предложения, но у меня все еще была проблема с java.lang.outOfMemoryError. После долгих доработок, наконец, сработало уменьшение размеров изображения (и размера). Изначально у меня были изображения размером 800 х 1000 сортов. Я масштабировал их примерно до 60 x 80 (потому что это то, что мне было нужно), и это сработало!

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

person Rudra    schedule 20.03.2015
comment
как бы вы это в java? - person learner; 09.08.2015
comment
Вы не уменьшаете изображение в Java, по крайней мере, я не знаю, как это сделать. Вы можете сделать это в MS Paint или использовать функцию сжатия изображений в MS Photoviewer. - person Rudra; 21.09.2015