8

我正在使用android:background为 android 布局提供背景图像。
放置一些图像后,我得到了这个异常:

08-24 00:40:19.237: E/dalvikvm-heap(8533): Out of memory on a 36000016-byte allocation.


如何在android上使用大图像作为背景?
我可以扩展应用程序堆内存吗?还是不好做?

4

6 回答 6

8

请看看我的相关问题:

高分辨率图像 - OutOfMemoryError

通过保持背景图像尽可能小,尽量减少应用程序的内存使用。

这可以通过以下方式完成:

  • 裁剪图像以使其适合屏幕
  • 在应用程序中使用之前进一步压缩图像(使用例如 Photoshop)
  • 使用以下方法加载您的位图
  • 不需要记录器时立即回收位图
  • 确保不要在内存中保留它的多个实例
  • 使用位图后将引用设置为 null

确保您设置为背景的图像已正确加载(例如裁剪尺寸,例如适合屏幕尺寸)并在不再需要时立即从内存中释放。

确保内存中只有一个 Bitmap 实例。显示后,调用recycle()并将您的引用设置为 null。

这是您可以加载图像的方式:

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 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) {

        // Calculate ratios of height and width to requested height and width
        final int heightRatio = Math.round((float) height / (float) reqHeight);
        final int widthRatio = Math.round((float) width / (float) reqWidth);

        // Choose the smallest ratio as inSampleSize value, this will guarantee
        // a final image with both dimensions larger than or equal to the
        // requested height and width.
        inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;
    }

    return inSampleSize;
}

感谢Adam Stelmaszczyk提供了这段漂亮的代码。

于 2013-08-23T22:11:04.067 回答
6

由于布局中的背景图像,我遇到了类似的问题。图像内存分配的正常大小应该是高*宽*4 字节(在 ARGB_8888 模式下,默认模式)。

如果您在显示一个活动时看到并分配了 30MB,那么肯定有一些问题。检查您是否将背景图像放置在可绘制文件夹中。在这种情况下,系统必须将该图像缩放到屏幕的特定密度,从而导致大量内存开销。

解决方案:

  1. 在每个可绘制文件夹(mdpi、hdpi、xhdpi...)中放置特定版本的背景图像。
  2. 将背景图像放在一个名为“drawable-nodpi”的特殊资源文件夹中。系统不会尝试缩放放置在此目录中的图像,因此只会执行拉伸过程并且分配的内存将是预期的。

此答案中的更多信息

希望这可以帮助。

于 2014-01-17T10:38:34.627 回答
5

我遇到了同样的问题并通过以下方式解决了它:

  1. 创建一个drawable-nodpi 文件夹并将你的背景图片放在那里。

  2. 使用 Picasso 显示图像http://square.github.io/picasso/

使用 .fit() 和 .centerCrop() 显示它们,如果需要,毕加索会缩放图像

ImageView ivLogo = (ImageView) findViewById(R.id.ivLogo);
Picasso.with(getApplicationContext())
   .load(R.drawable.logo)
   .fit()
   .centerCrop()
   .into(ivLogo);

如果您确实以某种方式耗尽了内存,Picasso 将根本不显示图像,而不是给您一个 OOM 错误。我希望这有帮助!

于 2016-01-05T11:20:38.930 回答
1

我可以扩展应用程序堆内存吗?

是的你可以。只需android:largeHeap:="true"在您的 Manifest.xml 中设置。

   <application
        android:name="com.pepperonas.libredrive.App"
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:largeHeap="true"
        android:label="@string/app_name"
        android:launchMode="standard">
于 2015-12-14T16:46:50.553 回答
0

使用 Glide 这将帮助您缓存图像并从内存中加载

Glide  
    .with(/*context*/)
    .load(/*urlToImage*/)
    .thumbnail(0.5f/*scale*/)  //you can even downscale the image
    .into(imageView);

其次,使用 Glide,您可以通过使用OnScrollChangedListener

if(scrollState == SCROLL_STATE_IDLE){
    Glide.with(this /*context*/).resumeRequests();
} else if(scrollState == SCROLL_STATE_TOUCH_SCROLL ||
          scrollState == SCROLL_STATE_FLING){
 Glide.with(this).pauseRequests();
}
于 2018-09-17T23:35:45.437 回答
0

对于位图 Glide 是最好的。

Glide.with(getContext()).load(img_url_1).apply(new RequestOptions().override(Target.SIZE_ORIGINAL)).into(imageView1);
于 2019-01-05T05:48:20.293 回答