【问题标题】:Android Out of memory error in ImageviewImageview中的Android内存不足错误
【发布时间】:2016-01-17 02:45:07
【问题描述】:

我需要在我的应用中设置背景图片。我使用了一个 imageview 并试图以编程方式设置它的背景。我收到“内存不足错误”。我在 SO 上阅读了其他帖子,并更改了我的代码以仅根据屏幕高度和宽度获取图像。我尝试了其他一些事情,但仍然遇到同样的错误。请帮忙。

谢谢。

    @Override
protected void onResume() {
    super.onResume();

    ivBackground.setImageBitmap(decodeSampledBitmapFromResource(getResources(), R.drawable.themes, getDisplayWidth(), getDisplayHeight()));
    ivBackground.setScaleType(ScaleType.CENTER_CROP);
}

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



public int getDisplayHeight(){
    DisplayMetrics dm = new DisplayMetrics();
    getWindowManager().getDefaultDisplay().getMetrics(dm);
    return dm.heightPixels;
}

public int getDisplayWidth(){
    DisplayMetrics dm = new DisplayMetrics();
    getWindowManager().getDefaultDisplay().getMetrics(dm);
    return dm.widthPixels;
}



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

xml 布局

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        >
    <ImageView android:id="@+id/ivBackground"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:scaleType="centerCrop"/>

    <android.support.v4.view.ViewPager

        android:id="@+id/pager"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".MainPage"
         />

【问题讨论】:

  • 您是尝试在 Asynctask 中并行下载图像还是尝试将图像存储在局部变量中..?
  • 为什么要在 onResume() 中设置图片??它根据活动生命周期调用了多次
  • 我在 onresume() 中这样做,因为背景图像是根据应用程序的主题设置的。用户可以从应用程序的任何位置选择主题。每当用户回到页面时,我们需要检查主题并相应地设置背景。我没有在上面的代码中粘贴所有细节。如果我在 oncreate 中设置背景图像,则每次用户返回活动时背景都不会改变
  • 你应该检查而不是直接设置。
  • @Manmohan。很抱歉没有知道如何使用 check..

标签: android


【解决方案1】:

我没有“声誉”来发表评论,所以发布答案。 这就是我认为正在发生的事情。 活动是第一次开始,所以 imageview 没有任何东西可以显示。

  • onResume 位图绑定到 imageview
  • onPause 活动暂停
  • OnResume 再次出现,这是棘手的部分。由于活动没有被破坏(我假设,你必须检查)位图仍然绑定到 imageView。当这条线被称为“ivBackground.setImageBitmap”时,它将调用“decodeSampledBitmapFromResource”方法来根据屏幕大小获取位图。这最终会创建一个缩小到屏幕尺寸的位图,因此将在内存中加载 2 个位图并在短时间内加载。并且当您加载全屏大小的位图时,内存中每个位图可能需要 20-25 mb。因此这可能会造成“内存不足”的情况。

解决方案:在 onPause 方法中设置 setImageBitmap null 对我有用 .

【讨论】:

    【解决方案2】:

    我通过这样做解决了这个错误 - 在我的情况下,图像尺寸对于我的手机来说太大了,所以我必须动态调整它的大小,然后才能将其加载到图像视图中。

    这就是我所做的:

    第 1 步:

    我通过How do I get the ScreenSize programmatically in android发现了我的屏幕分辨率是多少

        WindowManager wm = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
        Display display = wm.getDefaultDisplay();
        DisplayMetrics metrics = new DisplayMetrics();
        display.getMetrics(metrics);
        int width = metrics.widthPixels;
        int height = metrics.heightPixels;
    

    第 2 步:

    然后我动态调整位图的大小:

        Bitmap bm = drawableToBitmap(ContextCompat.getDrawable(this, R.drawable.cloud_plane));
        Bitmap bitmapsimplesize = Bitmap.createScaledBitmap(bm, width, height, true);
        bm.recycle();
        background.setImageBitmap(bitmapsimplesize);
    

    drawableToBitmap 方法可以在这里找到:How to convert a Drawable to a Bitmap?

    public static Bitmap drawableToBitmap (Drawable drawable) {
        Bitmap bitmap = null;
    
        if (drawable instanceof BitmapDrawable) {
            BitmapDrawable bitmapDrawable = (BitmapDrawable) drawable;
            if(bitmapDrawable.getBitmap() != null) {
                return bitmapDrawable.getBitmap();
            }
        }
    
        if(drawable.getIntrinsicWidth() <= 0 || drawable.getIntrinsicHeight() <= 0) {
            bitmap = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888); // Single color bitmap will be created of 1x1 pixel
        } else {
            bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
        }
    
        Canvas canvas = new Canvas(bitmap);
        drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
        drawable.draw(canvas);
        return bitmap;
    }
    

    【讨论】:

      【解决方案3】:

      只需将largeHeap="true" 放入应用程序标签(AndroidManifest.xml)

      <application
          android:icon="@drawable/ic_launcher"
          android:label="@string/app_name"
          android:largeHeap="true"
          android:theme="@android:style/Theme.Black.NoTitleBar" >
      

      我想它会对你有所帮助。
      谢谢。

      【讨论】:

      • 大堆更频繁的垃圾收集。所以android:largeHeap="true"要慎用
      • @Raghunandan 那么有什么选择呢?因为它需要更多的堆内存。
      • 请阅读developer.android.com/training/articles/memory.html。引用文档但是,请求大堆的能力仅适用于一小部分可以证明需要消耗更多 RAM 的应用程序(例如大型照片编辑应用程序)。 永远不要仅仅因为你的内存用完并且需要快速修复就请求一个大堆——只有在你知道所有内存被分配到哪里以及为什么必须保留它时才应该使用它 .
      【解决方案4】:

      在 Activity 上添加以下代码:

        @Override
              public void onDestroy(){
      
                      bitmap.recycle();
      
                  System.gc();
                  super.onDestroy();
      
              }
      

      【讨论】:

      • 我不确定如何使用 bitmap.recycle()。我没有直接使用位图。请帮忙
      • ivBackground.setImageBitmap(decodeSampledBitmapFromResource(getResources(), R.drawable.themes, getDisplayWidth(), getDisplayHeight())); ivBackground.setScaleType(ScaleType.CENTER_CROP);
      • 位图位图=decodeSampledBitmapFromResource(getResources(), R.drawable.themes, getDisplayWidth(), getDisplayHeight());ivBackground.setImageBitmap(bitmap); ivBackground.setScaleType(ScaleType.CENTER_CROP);
      • 我仍然不确定您输入的代码中的回收部分在哪里。不过,感谢您的建议。我对你的回答投了赞成票..
      • 谢谢..recycle()是Bitmap类的内置函数,用于刷新位图,当activity销毁时需要刷新位图,在onResume()中
      【解决方案5】:

      我在上面的代码中添加了以下内容并让它工作。它或多或少与其他人在这里提到的有关。所以,谢谢大家的帮助。

      @Override
      protected void onDestroy() {
          System.gc();
          super.onDestroy();
          ivBackground.setImageBitmap(null);
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-12-08
        • 1970-01-01
        • 2013-01-17
        • 2012-03-07
        • 1970-01-01
        • 2013-11-01
        相关资源
        最近更新 更多