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
,