【问题标题】:High resolution Image - OutOfMemoryError高分辨率图像 - OutOfMemoryError
【发布时间】:2013-08-25 11:22:34
【问题描述】:

我正在为 Galaxy S4 开发一个应用程序。 应用程序的要求之一是拥有一个包含 1920x1080 像素的图像的 SplashScreen。它是一个高质量的 .jpeg 图像,图像大小约为 2 兆字节

问题是我一启动应用程序就会收到 OutOfMemoryError。我很震惊,这已经发生在只有 2 兆字节大小的图像上? 如何解决此问题并显示图像?

不能更改图像的尺寸或大小。

SplashScreen.java

public class Splashscreen extends Activity {

private static final int SPLASH_DURATION = 2000;
private boolean isBackPressed = false; 

@Override
protected void onCreate(Bundle savedInstanceState) {

    requestWindowFeature(Window.FEATURE_NO_TITLE);
    getWindow().setFlags(LayoutParams.FLAG_FULLSCREEN, LayoutParams.FLAG_FULLSCREEN);
    super.onCreate(savedInstanceState);
    setContentView(R.layout.splashscreen);

    Handler h = new Handler();

    h.postDelayed(new Runnable() {

        @Override
        public void run() {

            // check if the backbutton has been pressed within the splash_duration
            if(!isBackPressed) { 

                Intent i = new Intent(Splashscreen.this, MainActivity.class);
                i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
                Splashscreen.this.startActivity(i);
                overridePendingTransition(R.anim.short_fade_in, R.anim.short_fade_out);
            }       

            finish();
        }
    }, SPLASH_DURATION);
}

@Override
public void onBackPressed() {

    isBackPressed = true;
    super.onBackPressed();
}
}

还有splashscreen.xml

    <ImageView 
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/ivSplashScreenImage"
        android:layout_width="match_parent"
        android:layout_height="match_parent" 
        android:scaleType="fitXY"
        android:src="@drawable/high_res_splashscreen_image"/>

其他信息:

有时,(当有大量设备内存可用时)应用能够通过启动屏幕,但随后,应用的内存消耗简直是疯狂(大约 100 兆字节)。即使我关闭 SplashScreen Activity 并完成()它,似乎 对 ImageView / Image 的引用保存在内存中。

如何减少巨大的内存消耗?

当我不显示启动画面时,我的应用只消耗大约 35MB 的记忆。使用 SplashScreen 图像,其大小约为 100MB。

【问题讨论】:

  • 你的 res 文件夹里是不是有很多图片文件??
  • 是的,我有大约 40 个图像文件。但它们不是很大(大多数只是图标),大小在 10 到 50kb 之间。

标签: android image bitmap android-imageview out-of-memory


【解决方案1】:

三个对你有帮助的提示:

  1. 使用它来加载您的图片,来自Loading Large Bitmaps Android documentation

    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;
    }
    
  2. 确保内存中只有一个 Bitmap 实例。显示后,调用recycle() 并将您的引用设置为null。您可以使用Memory Allocation Tracker 查看分配的内容。您还可以按照 cmets 中的建议阅读 HPROF 文件。

  3. 默认使用ARGB_8888像素格式,这意味着每个像素4个字节。很好的文章:Bitmap quality, banding and dithering。您的图像是 JPEG,因此它没有透明度,因此您在 alpha 通道的每个像素上浪费了 1 个字节。这不太可能,但也许质量可以接受,您可以使用更经济的格式。 Take 看看他们。例如可能RGB_565。像素需要 2 个字节,因此您的图像会轻 50%。您可以启用抖动以提高RGB_565 的质量。

【讨论】:

  • 谢谢,我会试试的。请查看我的更新答案和“附加信息”
  • 我将 .xml 文件中的图像资源设置为“@null”,现在像这样加载图像:“((ImageView) findViewById(R.id.ivSplashScreenImage)).setImageBitmap(decodeSampledBitmapFromResource( getResources(), R.drawable.highres, 1920, 1080));"我现在可以通过闪屏,但我的应用程序内存消耗仍然在 90MB 左右。 (没有启动画面,它的大小为 35-40mb)
  • 理论上,1920x1080 大小的位图应该只有 8MB 左右。你能看一下 HPROF 转储以确保你只分配这些位图之一吗?现在您正在手动加载图像,您应该确保在启动画面关闭后回收它并取消您对它的引用。 Memory Analysis for Android Applications
  • 抱歉,很遗憾,将图像更改为压缩它不是一个选项 :( 但是,回收完成了这项工作。非常感谢您的帮助!
【解决方案2】:

我遇到了类似的问题,解决方法很简单。将您的高分辨率 1920x1080 像素图像放在 drawable-nodpi 目录中。 无论当前屏幕的密度如何,系统都不会缩放带有此限定符的资源,这会导致 OutOfMemoryError,因此问题应该会消失。

请查看 Android 文档:http://developer.android.com/intl/es/guide/practices/screens_support.html

希望对你有帮助。

【讨论】:

    猜你喜欢
    • 2014-11-20
    • 2017-08-23
    • 2017-11-26
    • 1970-01-01
    • 2011-04-07
    • 1970-01-01
    • 1970-01-01
    • 2020-06-04
    • 2018-11-28
    相关资源
    最近更新 更多