ФАТИЧЕСКОЕ ИСКЛЮЧЕНИЕ: основной java.lang.OutOfMemoryError в android.graphics.BitmapFactory.nativeDecodeStream (собственный метод)

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

LogCat

    02-18 12:25:05.426: E/AndroidRuntime(4545): FATAL EXCEPTION: main
02-18 12:25:05.426: E/AndroidRuntime(4545): java.lang.OutOfMemoryError
02-18 12:25:05.426: E/AndroidRuntime(4545):     at android.graphics.BitmapFactory.nativeDecodeStream(Native Method)
02-18 12:25:05.426: E/AndroidRuntime(4545):     at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:493)
02-18 12:25:05.426: E/AndroidRuntime(4545):     at android.graphics.BitmapFactory.decodeFile(BitmapFactory.java:299)
02-18 12:25:05.426: E/AndroidRuntime(4545):     at com.oneplc.viessmannapp.imageslider.adapter.FullScreenImageAdapter.instantiateItem(FullScreenImageAdapter.java:59)
02-18 12:25:05.426: E/AndroidRuntime(4545):     at android.support.v4.view.ViewPager.addNewItem(ViewPager.java:832)
02-18 12:25:05.426: E/AndroidRuntime(4545):     at android.support.v4.view.ViewPager.populate(ViewPager.java:1016)
02-18 12:25:05.426: E/AndroidRuntime(4545):     at android.support.v4.view.ViewPager.populate(ViewPager.java:914)
02-18 12:25:05.426: E/AndroidRuntime(4545):     at android.support.v4.view.ViewPager$3.run(ViewPager.java:244)
02-18 12:25:05.426: E/AndroidRuntime(4545):     at android.support.v4.view.ViewPager.completeScroll(ViewPager.java:1761)
02-18 12:25:05.426: E/AndroidRuntime(4545):     at android.support.v4.view.ViewPager.onInterceptTouchEvent(ViewPager.java:1894)
02-18 12:25:05.426: E/AndroidRuntime(4545):     at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1629)
02-18 12:25:05.426: E/AndroidRuntime(4545):     at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:1957)
02-18 12:25:05.426: E/AndroidRuntime(4545):     at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1684)
02-18 12:25:05.426: E/AndroidRuntime(4545):     at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:1957)
02-18 12:25:05.426: E/AndroidRuntime(4545):     at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1684)
02-18 12:25:05.426: E/AndroidRuntime(4545):     at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:1957)
02-18 12:25:05.426: E/AndroidRuntime(4545):     at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1684)
02-18 12:25:05.426: E/AndroidRuntime(4545):     at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:1957)
02-18 12:25:05.426: E/AndroidRuntime(4545):     at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1684)
02-18 12:25:05.426: E/AndroidRuntime(4545):     at com.android.internal.policy.impl.PhoneWindow$DecorView.superDispatchTouchEvent(PhoneWindow.java:1917)
02-18 12:25:05.426: E/AndroidRuntime(4545):     at com.android.internal.policy.impl.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:1371)
02-18 12:25:05.426: E/AndroidRuntime(4545):     at android.app.Activity.dispatchTouchEvent(Activity.java:2364)
02-18 12:25:05.426: E/AndroidRuntime(4545):     at com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchTouchEvent(PhoneWindow.java:1865)
02-18 12:25:05.426: E/AndroidRuntime(4545):     at android.view.View.dispatchPointerEvent(View.java:5721)
02-18 12:25:05.426: E/AndroidRuntime(4545):     at android.view.ViewRootImpl.deliverPointerEvent(ViewRootImpl.java:2890)
02-18 12:25:05.426: E/AndroidRuntime(4545):     at android.view.ViewRootImpl.handleMessage(ViewRootImpl.java:2466)
02-18 12:25:05.426: E/AndroidRuntime(4545):     at android.view.ViewRootImpl.processInputEvents(ViewRootImpl.java:845)
02-18 12:25:05.426: E/AndroidRuntime(4545):     at android.view.ViewRootImpl.handleMessage(ViewRootImpl.java:2475)
02-18 12:25:05.426: E/AndroidRuntime(4545):     at android.os.Handler.dispatchMessage(Handler.java:99)
02-18 12:25:05.426: E/AndroidRuntime(4545):     at android.os.Looper.loop(Looper.java:137)
02-18 12:25:05.426: E/AndroidRuntime(4545):     at android.app.ActivityThread.main(ActivityThread.java:4424)
02-18 12:25:05.426: E/AndroidRuntime(4545):     at java.lang.reflect.Method.invokeNative(Native Method)
02-18 12:25:05.426: E/AndroidRuntime(4545):     at java.lang.reflect.Method.invoke(Method.java:511)
02-18 12:25:05.426: E/AndroidRuntime(4545):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:784)
02-18 12:25:05.426: E/AndroidRuntime(4545):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:551)
02-18 12:25:05.426: E/AndroidRuntime(4545):     at dalvik.system.NativeStart.main(Native Method)

ОТВЕТСТВЕННЫЙ КЛАСС / FullScreenImageAdapter.java в строке: 59

    public class FullScreenImageAdapter extends PagerAdapter {

    private Activity _activity;
    private ArrayList<String> _imagePaths;
    private LayoutInflater inflater;

    // constructor
    public FullScreenImageAdapter(Activity activity,
            ArrayList<String> imagePaths) {
        this._activity = activity;
        this._imagePaths = imagePaths;
    }

    @Override
    public int getCount() {
        return this._imagePaths.size();
    }

    @Override
    public boolean isViewFromObject(View view, Object object) {
        return view == ((RelativeLayout) object);
    }

    @Override
    public Object instantiateItem(ViewGroup container, int position) {
        TouchImageView imgDisplay;
        Button btnClose;

        inflater = (LayoutInflater) _activity
                .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        View viewLayout = inflater.inflate(R.layout.layout_fullscreen_image, container,
                false);

        imgDisplay = (TouchImageView) viewLayout.findViewById(R.id.imgDisplay);
        btnClose = (Button) viewLayout.findViewById(R.id.btnClose);

        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inPreferredConfig = Bitmap.Config.ARGB_8888;
        Bitmap bitmap = BitmapFactory.decodeFile(_imagePaths.get(position), options);
        imgDisplay.setImageBitmap(bitmap);

        // close button click event
        btnClose.setOnClickListener(new View.OnClickListener() {            
            @Override
            public void onClick(View v) {
                _activity.finish();
            }
        });

        ((ViewPager) container).addView(viewLayout);

        return viewLayout;
    }

    @Override
    public void destroyItem(ViewGroup container, int position, Object object) {
        ((ViewPager) container).removeView((RelativeLayout) object);

    }
}

КОММЕНТАРИИ

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

Есть идеи, как я могу решить эту проблему?


person AndroidKrayze    schedule 18.02.2014    source источник
comment
вы можете использовать универсальный класс imageLoader .....   -  person Piyush    schedule 18.02.2014
comment
Так это реализация в полноэкранном режиме Activity ??? Я сейчас реализую то же самое и отлично работаю для меня.   -  person Piyush    schedule 18.02.2014
comment
Это очень странно, потому что когда я запускаю эту функцию отдельно, она работает нормально, но когда я включаю ее в свое приложение, я получаю ошибку памяти ...   -  person AndroidKrayze    schedule 18.02.2014
comment
Да, потому что может быть вы используете изображения с высоким разрешением ?? А если эти изображения загружаются с сервера?   -  person Piyush    schedule 18.02.2014
comment
Итак, теперь у вас есть это?   -  person Piyush    schedule 18.02.2014
comment
Я использую одинаковое разрешение в обоих приложениях, но только в одном ломается :( .. Все файлы с SDCARD   -  person AndroidKrayze    schedule 18.02.2014
comment
Хорошо. Мой вопрос в том, что если вы используете статические изображения или исходите с сервера?   -  person Piyush    schedule 18.02.2014
comment
Вам нужно узнать больше об обработке растровых изображений в Android, например, в ссылке, которую я предоставил в своем ответе ...   -  person Billda    schedule 18.02.2014


Ответы (4)


Если документы Google не помогли (а в них есть несколько изящных приемов), в крайнем случае вы можете попробовать добавить android:largeHeap="true" к тегу <application> в AndroidManifest.xml. Но на самом деле в крайнем случае.

person milosmns    schedule 27.12.2014

Вам следует ознакомиться с этой статьей на сайте разработчиков Android http://developer.android.com/training/displaying-bitmaps/index.html. Вы должны загружать растровое изображение асинхронно, потому что вы декодируете файл и его дорогостоящую операцию, и вы также должны сначала загрузить размер растрового изображения, а затем масштабировать его до реального размера изображения.

person Billda    schedule 18.02.2014

вы должны использовать это ......

      @Override
    public Object instantiateItem(ViewGroup container, int position) {
        final TouchImageView imgDisplay;

        inflater = (LayoutInflater) _activity
                .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        View viewLayout = inflater.inflate(
                R.layout.layout_fullscreen_image, container, false);

        imgDisplay = (TouchImageView) viewLayout
                .findViewById(R.id.imgDisplay);
        final ProgressBar spinner = (ProgressBar) viewLayout
                .findViewById(R.id.loading);
        // btnShare = (Button) viewLayout.findViewById(R.id.btnShare);

        imageLoader.displayImage(_imagePaths.get(position).get("url"),
                imgDisplay, options, new ImageLoadingListener() {
                    @Override
                    public void onLoadingStarted() {
                        spinner.setVisibility(View.VISIBLE);
                    }

                    @Override
                    public void onLoadingFailed(FailReason failReason) {
                        String message = null;
                        switch (failReason) {
                        case IO_ERROR:
                            message = "Input/Output error";
                            break;
                        case OUT_OF_MEMORY:
                            message = "Out Of Memory error";
                            break;
                        case UNKNOWN:
                            message = "Unknown error";
                            break;
                        }
                        Toast.makeText(FullScreenViewActivity.this,
                                message, Toast.LENGTH_SHORT).show();

                        spinner.setVisibility(View.GONE);
                        imgDisplay
                                .setImageResource(android.R.drawable.ic_delete);
                    }

                    @Override
                    public void onLoadingComplete(Bitmap loadedImage) {
                        spinner.setVisibility(View.GONE);
                        Animation anim = AnimationUtils
                                .loadAnimation(FullScreenViewActivity.this,
                                        R.anim.fade_in);
                        imgDisplay.setAnimation(anim);
                        anim.start();

                    }

                    @Override
                    public void onLoadingCancelled() {
                        // Do nothing
                    }
                });

        ((ViewPager) container).addView(viewLayout, 0);

        return viewLayout;
    }

    @Override
    public void destroyItem(ViewGroup container, int position, Object object) {
        ((ViewPager) container).removeView((FrameLayout) object);

    }
}

Добавьте этот код в метод onCreate () ..

      private DisplayImageOptions options;

      options = new DisplayImageOptions.Builder()
            .showImageForEmptyUri(R.drawable.ic_launcher).cacheOnDisc()
            .imageScaleType(ImageScaleType.IN_SAMPLE_INT).build();

Добавьте файл jar universal-image-loader-1.6.1-with-src.jar в папку libs.

ОБНОВЛЕНИЕ:

 private DisplayImageOptions options;
 public FullScreenImageAdapter(Activity activity,
        ArrayList<String> imagePaths) {
    this._activity = activity;
    this._imagePaths = imagePaths;
    options = new DisplayImageOptions.Builder()
            .showImageForEmptyUri(R.drawable.ic_launcher).cacheOnDisc()
            .imageScaleType(ImageScaleType.IN_SAMPLE_INT).build();
 }
person Piyush    schedule 18.02.2014
comment
Сейчас попробую Пиюш! - person AndroidKrayze; 18.02.2014
comment
Пиюш, мой класс расширяет адаптер и не является действием, а это значит, что у меня нет метода onCreate. - person AndroidKrayze; 18.02.2014
comment
вы также можете добавить его в свой конструктор класса адаптера. - person Piyush; 18.02.2014
comment
Хорошо, я закончил урок, но получаю несколько ошибок: - person AndroidKrayze; 18.02.2014
comment
Хорошо, удалите одну вещь из этого конструктора. А переходники другого класса делали? Если да, то просто сделайте этот класс внутри активности, из которой вызывается ваш класс адаптера. Я иду сейчас. Так что, если у вас все еще есть запрос, оставьте его здесь. - person Piyush; 18.02.2014
comment
Хорошо, я завершил работу с классом, но получаю несколько ошибок на ImageLoader.displayImage (_imagePaths.get (position) .get (url), ‹Метод get (String) не определен для типа String› || switch (failReason) ‹Невозможно включить значение типа FaiLReason. Разрешены только конвертируемые значения int или enum veriables ›|| R.anim.fade in‹ anim не может быть разрешен или не является полем ›Обратите внимание, что я использую универсальный загрузчик-1.9.1, может не найти 1.6 - person AndroidKrayze; 18.02.2014
comment
давайте продолжим обсуждение в чате - person AndroidKrayze; 18.02.2014

если кто-то пытается получить изображения из sqlite и получить ошибку outOfMemory, попробуйте следующее:

cursor = adapter.getAllrecords(); //get your table records in cursor

//moving to the current position in cursor 
cursor.moveToPosition(position);

byte [] image = cursor.getBlob(cursor.getColumnIndex("image"));

 BitmapFactory.Options options = new  BitmapFactory.Options();
 options.inJustDecodeBounds = true;
 bitmapImage = BitmapFactory.decodeByteArray(image, 0, image.length, options);
 imageView.setImageBitmap(decodeSampledBitmapFromResource(80, 80));//pass height and             
                                                      //width as per your requirement 



public  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  Bitmap decodeSampledBitmapFromResource(int reqWidth, int reqHeight) {

            // First decode with inJustDecodeBounds=true 
                to check dimensions
            final BitmapFactory.Options options = new BitmapFactory.Options();
            options.inJustDecodeBounds = true;
            BitmapFactory.decodeByteArray(image, 0, image.length, options);

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

            // Decode bitmap with inSampleSize set
            options.inJustDecodeBounds = false;
            return BitmapFactory.decodeByteArray(image, 0, image.length, options);
        }

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

person Murli    schedule 05.07.2014