ViewFlipper внутри ViewPager - OutOfMemory

У меня есть 20 изображений в моем приложении. Все изображения имеют разрешение 640 * 360 и не более 60 КБ каждое.

Я использую Viewpager, чтобы скользить изображения. И используйте ViewFlipper внутри ViewPager, чтобы перевернуть изображения. Когда пользователь нажимает на него, я показываю соответствующий текст для изображения.

Проблема в том, что я получаю исключение OutOfMemory, когда я провожу назад и вперед 5 раз. Я читаю различные темы Stackru здесь!, Здесь!, Здесь! и эффективная обработка больших растровых изображений! но не в состоянии решить проблему,

Вот код,

В Main_Fragment.java,

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {

--- some code ---

--- some more code --- 

View v = inflater.inflate(R.layout.main_fragment, container,false);

viewAnimator = ((ViewAnimator) v.findViewById(R.id.cardFlipper));

TextView caption_text = (TextView) v.findViewById(R.id.caption_text);
caption_text.setText(caption.toUpperCase());

ImageView main_img = (ImageView) v.findViewById(R.id.main_img);

int mainimg_resID = getResources().getIdentifier(mainimg,"drawable",context.getPackageName());

Bitmap icon = decodeSampledBitmapFromResource(getResources(),mainimg_resID,640,360);

main_img.setImageBitmap(icon);

viewAnimator.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
  AnimationFactory.flipTransition((ViewAnimator) v,FlipDirection.LEFT_RIGHT);
}
});

return v;
}


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

Подскажите, пожалуйста, что я делаю не так? Это сводит меня с ума в течение последних нескольких дней:(

1 ответ

Да, я видел что-то очень не то, что ты делаешь

Bitmap icon = decodeSampledBitmapFromResource(getResources(),mainimg_resID,640,360);

Вы все неправильно поняли: reqHeight а также reqWidth параметры должны быть шириной и высотой просмотра изображения, а не исходным размером изображения!! это все что calculateInSampleSize() это все о..

Итак, вы должны сделать следующее:

Bitmap icon = decodeSampledBitmapFromResource(getResources(),mainimg_resID,main_img.getWidth(), main_img.getHeight());

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

и, кстати, тот факт, что размер используемого вами ресурса составляет всего 60 КБ, ничего не меняет. на самом деле - размер памяти изображения (в килобайтах / мегапикселях) не влияет на выделенное растровое изображение. только разрешение имеет значение!

РЕДАКТИРОВАТЬ

потому что размеры imageView по-прежнему равны нулю на onCreateView() Метод - вы должны формировать декодирование только после того, как оно получило его размеры:

--- some code ---

--- some more code --- 

View v = inflater.inflate(R.layout.main_fragment, container,false);

viewAnimator = ((ViewAnimator) v.findViewById(R.id.cardFlipper));

TextView caption_text = (TextView) v.findViewById(R.id.caption_text);
caption_text.setText(caption.toUpperCase());

final ImageView main_img = (ImageView) v.findViewById(R.id.main_img);

ViewTreeObserver vto = main_img.getViewTreeObserver();
vto.addOnGlobalLayoutListener(new OnGlobalLayoutListener() {

    @Override
    public void onGlobalLayout() {

            final ViewTreeObserver obs = main_img.getViewTreeObserver();

            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
            obs.removeOnGlobalLayoutListener(this);
            } else {
               obs.removeGlobalOnLayoutListener(this);
            }

            // do here the image decoding + setting the image to the image view
            Bitmap icon = decodeSampledBitmapFromResource(getResources(),mainimg_resID,main_img.getWidth(), main_img.getHeight());

            //  setImage....
      }

});

viewAnimator.setOnClickListener(new OnClickListener() {
    @Override
    public void onClick(View v) {
    AnimationFactory.flipTransition((ViewAnimator) v,FlipDirection.LEFT_RIGHT);
    }
});

return v;

РЕДАКТИРОВАТЬ 2

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

Другие вопросы по тегам