内存不足错误ImageView问题

Max*_*Max 32 android out-of-memory

我在Android的编程新和我,说我的应用程序运行的内存,这所示例我从一本书上抄,它正在与小图片的分辨率,但一个错误,当我加了几张照片具有更大的分辨率出来出现内存错误,可能是我做错了或者只是不知道我还应该使用图像,如果有人知道我应该改变什么,以便这个错误不再出现,请求帮助.谢谢期待!

源代码:

public class ImageViewsActivity extends Activity {
//the images to display
Integer[] imageIDs={
        R.drawable.pic1,
        R.drawable.pic2,
        R.drawable.pic3,
        R.drawable.pic4,
        R.drawable.pic5
};  
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    final ImageView iv=(ImageView) findViewById(R.id.image1);

    Gallery gallery=(Gallery) findViewById(R.id.gallery);
    gallery.setAdapter(new ImageAdapter(this));
  gallery.setOnItemClickListener(new OnItemClickListener(){
        public void onItemClick(AdapterView<?> parent, View v, int position, long id){
            Toast.makeText(getBaseContext(), "pic"+(position+1)+" selected", Toast.LENGTH_SHORT).show();

            //display the image selected
            try{iv.setScaleType(ImageView.ScaleType.FIT_CENTER);
              iv.setImageResource(imageIDs[position]);}catch(OutOfMemoryError e){
                     iv.setImageBitmap(null);
                }
        }
    });


}

public class ImageAdapter extends BaseAdapter{
    private Context context;
    private int itemBackground;

    public ImageAdapter(Context c){
        context=c;
        //setting the style
        TypedArray a = obtainStyledAttributes(R.styleable.Gallery1);
        itemBackground = a.getResourceId(R.styleable.Gallery1_android_galleryItemBackground, 0);
        a.recycle();
    }

    //returns the number of images
    public int getCount() {
        // TODO Auto-generated method stub
        return imageIDs.length;
    }

    //returns the ID of an item
    public Object getItem(int position) {
        // TODO Auto-generated method stub
        return position;
    }

    //returns the ID of an item
    public long getItemId(int position) {
        // TODO Auto-generated method stub
        return position;
    }

    //returns an ImageView view
    public View getView(int position, View convertView, ViewGroup parent) {
        // TODO Auto-generated method stub
        ImageView iv= new ImageView(context);
        iv.setImageResource(imageIDs[position]);
        iv.setScaleType(ImageView.ScaleType.FIT_XY);
        iv.setLayoutParams(new Gallery.LayoutParams(150,120));
        iv.setBackgroundResource(itemBackground);

        return iv;
    }
}}
Run Code Online (Sandbox Code Playgroud)

错误在这里:

04-18 10:38:31.661: D/dalvikvm(10152): Debugger has detached; object registry had 442 entries
04-18 10:38:31.661: D/AndroidRuntime(10152): Shutting down VM
04-18 10:38:31.661: W/dalvikvm(10152): threadid=1: thread exiting with uncaught exception (group=0x4001d820)
04-18 10:38:31.691: E/AndroidRuntime(10152): FATAL EXCEPTION: main
04-18 10:38:31.691: E/AndroidRuntime(10152): java.lang.OutOfMemoryError: bitmap size exceeds VM budget
04-18 10:38:31.691: E/AndroidRuntime(10152):    at android.graphics.Bitmap.nativeCreate(Native Method)
04-18 10:38:31.691: E/AndroidRuntime(10152):    at android.graphics.Bitmap.createBitmap(Bitmap.java:499)
04-18 10:38:31.691: E/AndroidRuntime(10152):    at android.graphics.Bitmap.createBitmap(Bitmap.java:466)
04-18 10:38:31.691: E/AndroidRuntime(10152):    at android.graphics.Bitmap.createScaledBitmap(Bitmap.java:371)
04-18 10:38:31.691: E/AndroidRuntime(10152):    at android.graphics.BitmapFactory.finishDecode(BitmapFactory.java:539)
04-18 10:38:31.691: E/AndroidRuntime(10152):    at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:508)
04-18 10:38:31.691: E/AndroidRuntime(10152):    at android.graphics.BitmapFactory.decodeResourceStream(BitmapFactory.java:365)
04-18 10:38:31.691: E/AndroidRuntime(10152):    at android.graphics.drawable.Drawable.createFromResourceStream(Drawable.java:728)
04-18 10:38:31.691: E/AndroidRuntime(10152):    at android.content.res.Resources.loadDrawable(Resources.java:1740)
04-18 10:38:31.691: E/AndroidRuntime(10152):    at android.content.res.Resources.getDrawable(Resources.java:612)
04-18 10:38:31.691: E/AndroidRuntime(10152):    at android.widget.ImageView.resolveUri(ImageView.java:520)
04-18 10:38:31.691: E/AndroidRuntime(10152):    at android.widget.ImageView.setImageResource(ImageView.java:305)
04-18 10:38:31.691: E/AndroidRuntime(10152):    at image.view.GalleryView$ImageAdapter.getView(GalleryView.java:95)
04-18 10:38:31.691: E/AndroidRuntime(10152):    at android.widget.Gallery.makeAndAddView(Gallery.java:776)
04-18 10:38:31.691: E/AndroidRuntime(10152):    at android.widget.Gallery.fillToGalleryLeft(Gallery.java:695)
04-18 10:38:31.691: E/AndroidRuntime(10152):    at android.widget.Gallery.trackMotionScroll(Gallery.java:406)
04-18 10:38:31.691: E/AndroidRuntime(10152):    at android.widget.Gallery$FlingRunnable.run(Gallery.java:1397)
04-18 10:38:31.691: E/AndroidRuntime(10152):    at android.os.Handler.handleCallback(Handler.java:618)
04-18 10:38:31.691: E/AndroidRuntime(10152):    at android.os.Handler.dispatchMessage(Handler.java:123)
04-18 10:38:31.691: E/AndroidRuntime(10152):    at android.os.Looper.loop(Looper.java:154)
04-18 10:38:31.691: E/AndroidRuntime(10152):    at android.app.ActivityThread.main(ActivityThread.java:4668)
04-18 10:38:31.691: E/AndroidRuntime(10152):    at java.lang.reflect.Method.invokeNative(Native Method)
04-18 10:38:31.691: E/AndroidRuntime(10152):    at java.lang.reflect.Method.invoke(Method.java:552)
04-18 10:38:31.691: E/AndroidRuntime(10152):    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:917)
04-18 10:38:31.691: E/AndroidRuntime(10152):    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:674)
04-18 10:38:31.691: E/AndroidRuntime(10152):    at dalvik.system.NativeStart.main(Native Method)
Run Code Online (Sandbox Code Playgroud)

why*_*yoz 36

为了补充Ken的答案,这是一段可靠的代码,我认为在他设置之后我会把它打倒:

    if(imageView != null) {
        ((BitmapDrawable)imageView.getDrawable()).getBitmap().recycle();
    }
    imageView = (ImageView) view.findViewById(R.id.imageView);
    imageView.setImageResource(resID);
Run Code Online (Sandbox Code Playgroud)

注意:如果您尝试交换已经回收的图像,则无法使用此功能.你会在LOGCAT中得到这样的东西

画布:尝试使用回收的位图

所以,如果我不必异步加载一堆不同的图像,我现在所做的就是在处理片段和大背景图像时简单地将它放在onDestroy中:

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

    imageView.setImageDrawable(null);
}
Run Code Online (Sandbox Code Playgroud)


Ken*_*Ken 28

使用

((BitmapDrawable)imageView.getDrawable()).getBitmap().recycle();
Run Code Online (Sandbox Code Playgroud)

在换到新图像之前!!


Sak*_*boy 18

对于那些使用Glide图像加载库的人来说,仍然OutOfMemory Exception遇到这些问题,你可以做很多事情来Glide减少内存使用并希望能解决你的问题.这里有几个:

  • 不要android:scaleType="fitXY"在你的内心使用ImageView.所以如果你ImageView看起来像这样:

    <ImageView android:id="@android:id/icon"
           android:layout_width="@dimen/width"
           android:layout_height="@dimen/height"
           android:adjustViewBounds="true" 
           android:scaleType="fitXY" 
          <!-- DON'T USE "fitXY"! -->
    />
    
    Run Code Online (Sandbox Code Playgroud)

    改变ImageView使用不同的android:scaleType,最好是:fitCentercenterCrop.

  • 不要wrap_content在你的使用ImageView,而是使用match_parent或指定width/ height明确使用大小dp.如果你真的坚持wrap_content在你的使用中ImageView,至少设置一个android:maxHeight/ android:maxWidth.
  • dontAnimate()根据您的Glide.with()...要求关闭动画.
  • 如果您正在加载大量潜在的大图像(就像在列表/网格中那样),请thumbnail(float sizeMultiplier)在请求中指定加载.例如:

    Glide.with(context)
       .load(imageUri)
       .thumbnail(0.5f)
       .dontAnimate()
       .into(iconImageView);
    
    Run Code Online (Sandbox Code Playgroud)
  • 使用以下方法暂时降低Glide应用程序某些阶段的内存占用率:Glide.get(context).setMemoryCategory(MemoryCategory.LOW).

  • 仅在内存缓存中,如果你需要,你可以将其关闭:skipMemoryCache(true)在你的Glide.with()...请求.这仍然会将图像缓存到磁盘,这可能是您可能想要的,因为您已经在内存缓存之前.
  • 如果您Drawable从本地资源加载a ,请确保您尝试加载的图像不是太大了.网上有很多图像压缩工具.这些工具将缩小图像的大小,同时保持其外观质量.
  • 如果从本地资源加载使用.diskCacheStrategy(DiskCacheStrategy.NONE).
  • 深入onTrimMemory(int level)了解Android提供的回调,以Glide根据需要修剪缓存.防爆.

    @Override
    public void onTrimMemory(int level)
    {
        super.onTrimMemory(level);
        Glide.get(this).trimMemory(level);
    }
    
    Run Code Online (Sandbox Code Playgroud)
  • 如果在图像中显示图像,RecyclerView您可以明确清除Glide视图何时被回收,如下所示:

    @Override
    public void onViewRecycled(MyAdapter.MyViewHolder holder)
    {
        super.onViewRecycled(holder);
        Glide.clear(holder.imageView);
    }
    
    Run Code Online (Sandbox Code Playgroud)
  • 如果这仍然发生,即使你已经"尝试了一切",问题可能是你的应用程序(GASP!),并且Glide只是将它推向OutOfMemory Exception区域的一件事......所以一定要确保你没有应用程序中的任何内存泄漏.Android Studio提供用于识别应用程序中的内存消耗问题的工具.
  • 最后查看Glide的GitHub上问题页面,了解可能提供有关解决问题的深入见解的类似问题.回购管理得非常好,他们非常乐于助人.


Ivo*_*nov 6

图像有各种形状和大小.在许多情况下,它们比典型应用程序用户界面(UI)所需的大.例如,系统图库应用程序显示使用Android设备的相机拍摄的照片,这些照片的分辨率通常远高于设备的屏幕密度.

鉴于您正在使用有限的内存,理想情况下您只想在内存中加载较低分辨率的版本.较低分辨率版本应与显示它的UI组件的大小相匹配.具有更高分辨率的图像不提供任何可见的益处,但仍然占用宝贵的存储器并且由于额外的飞行缩放而产生额外的性能开销.

来源:有效地加载大位图

基于上面的信息,我建议你不要像这样设置图像:

setImageResource(resId);
Run Code Online (Sandbox Code Playgroud)

设置如下:

setScaledImage(yourImageView, resId);
Run Code Online (Sandbox Code Playgroud)

并复制和粘贴以下方法:

    private void setScaledImage(ImageView imageView, final int resId) {
        final ImageView iv = imageView;
        ViewTreeObserver viewTreeObserver = iv.getViewTreeObserver();
        viewTreeObserver.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
            public boolean onPreDraw() {
                iv.getViewTreeObserver().removeOnPreDrawListener(this);
                int imageViewHeight = iv.getMeasuredHeight();
                int imageViewWidth = iv.getMeasuredWidth();
                iv.setImageBitmap(
                        decodeSampledBitmapFromResource(getResources(),
                                resId, imageViewWidth, imageViewHeight));
                return true;
            }
        });
    }

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

    private 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;
    }
Run Code Online (Sandbox Code Playgroud)