2016-09-29 35 views
2

我在将图像加载到某些设备的屏幕上时遇到了问题。甚至当我解码图像时OOM错误

所有的屏幕都有一个图像,但它的相当高的图像。

以下是在图像尺寸

人像:

  • MDPI:360x1074
  • HDPI:540x1611
  • xhdpi:720x2148
  • xxhdpi:1080x3142

景观:

  • MDPI:640x705
  • 华电国际:960x1058
  • xhdpi:1280x1410
  • xxhdpi:1920x1035

我跟了:https://developer.android.com/training/displaying-bitmaps/load-bitmap.html也是这个http://successmatics.com/blog/loading-large-bitmaps-in-android-ui/,但他们基本上是相同的。

如果我加载一个小得多的图像说别的缩略图,它加载得很好。

在OnCreate

mImageView.setImageBitmap(
    ImageUtils.decodeSampledBitmapFromResource(getResources(), 
    R.drawable.image, 
    ImageUtils.getScreenWidth(getApplicationContext()), 
    ImageUtils.getScreenHeight(getApplicationContext()))); 
} 

方法加载图像用于解码图像(从上面的2个网址)

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

     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) { 
//--------i tried a sample size of 2. was hoping 3 would work---------// 
     inSampleSize *= 3; 
     } 
    } 

    return inSampleSize; 
    } 

    public static int getScreenWidth(Context context) { 
    DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics(); 
    return displayMetrics.widthPixels; 
    } 

    public static int getScreenHeight(Context context) { 
    DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics(); 
    return displayMetrics.heightPixels; 
    } 

任何人都不会有大的图像解码更好的办法,所以我不明白在OOM

有什么错我的代码(WHI CH从Android电子自理)

编辑:对不起忘了堆栈跟踪:

E/dalvikvm-heap: Out of memory on a 10391232-byte allocation. 
    I/dalvikvm: "main" prio=5 tid=1 RUNNABLE 
    I/dalvikvm: | group="main" sCount=0 dsCount=0 obj=0xb264b450 self=0xb8d604e0 
    I/dalvikvm: | sysTid=26630 nice=0 sched=0/0 cgrp=[fopen-error:2] handle=-1216986048 
    I/dalvikvm: | schedstat=(0 0 0) utm=117 stm=69 core=0 
    I/dalvikvm:  at android.graphics.BitmapFactory.nativeDecodeAsset(Native Method) 
    I/dalvikvm:  at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:500) 
    I/dalvikvm:  at android.graphics.BitmapFactory.decodeResourceStream(BitmapFactory.java:353) 
    I/dalvikvm:  at android.graphics.drawable.Drawable.createFromResourceStream(Drawable.java:781) 
    I/dalvikvm:  at android.content.res.Resources.loadDrawable(Resources.java:1935) 
    I/dalvikvm:  at android.content.res.TypedArray.getDrawable(TypedArray.java:601) 
    I/dalvikvm:  at android.widget.ImageView.<init>(ImageView.java:120) 
    I/dalvikvm:  at android.support.v7.widget.AppCompatImageView.<init>(AppCompatImageView.java:57) 
    I/dalvikvm:  at android.support.v7.widget.AppCompatImageView.<init>(AppCompatImageView.java:53) 
    I/dalvikvm:  at android.support.v7.app.AppCompatViewInflater.createView(AppCompatViewInflater.java:106) 
    I/dalvikvm:  at android.support.v7.app.AppCompatDelegateImplV7.createView(AppCompatDelegateImplV7.java:980) 
    I/dalvikvm:  at android.support.v7.app.AppCompatDelegateImplV7.onCreateView(AppCompatDelegateImplV7.java:1039) 
    I/dalvikvm:  at android.support.v4.view.LayoutInflaterCompatHC$FactoryWrapperHC.onCreateView(LayoutInflaterCompatHC.java:44) 
    I/dalvikvm:  at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:675) 
    I/dalvikvm:  at android.view.LayoutInflater.rInflate(LayoutInflater.java:746) 
    I/dalvikvm:  at android.view.LayoutInflater.rInflate(LayoutInflater.java:749) 
    I/dalvikvm:  at android.view.LayoutInflater.rInflate(LayoutInflater.java:749) 
    I/dalvikvm:  at android.view.LayoutInflater.inflate(LayoutInflater.java:489) 
    I/dalvikvm:  at android.view.LayoutInflater.inflate(LayoutInflater.java:396) 
    I/dalvikvm:  at android.view.LayoutInflater.inflate(LayoutInflater.java:352) 
    I/dalvikvm:  at android.support.v7.app.AppCompatDelegateImplV7.setContentView(AppCompatDelegateImplV7.java:280) 
    I/dalvikvm:  at android.support.v7.app.AppCompatActivity.setContentView(AppCompatActivity.java:140) 
    I/dalvikvm:  at com.myapp.app.item.protection.Protection.onCreate(Protection.java:31) 
    I/dalvikvm:  at android.app.Activity.performCreate(Activity.java:5008) 
    I/dalvikvm:  at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1079) 
    I/dalvikvm:  at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2023) 
    I/dalvikvm:  at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2084) 
    I/dalvikvm:  at android.app.ActivityThread.access$600(ActivityThread.java:130) 
    I/dalvikvm:  at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1195) 
    I/dalvikvm:  at android.os.Handler.dispatchMessage(Handler.java:99) 
    I/dalvikvm:  at android.os.Looper.loop(Looper.java:137) 
    I/dalvikvm:  at android.app.ActivityThread.main(ActivityThread.java:4745) 
    I/dalvikvm:  at java.lang.reflect.Method.invokeNative(Native Method) 
    I/dalvikvm:  at java.lang.reflect.Method.invoke(Method.java:511) 
    I/dalvikvm:  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:786) 
    I/dalvikvm:  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553) 
    I/dalvikvm:  at dalvik.system.NativeStart.main(Native Method) 

我使用目前唯一的图像加载库排球联网的图像。这是@Drawable文件中的资源。有2个版本,纵向和横向(不想拉伸)

感谢

+0

张贴您的logcat?你使用任何图书馆进行图片加载? – PN10

+0

请参阅编辑 – x10sion

回答

0

替换该行

options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight); 

它会解决你的问题

options.inSampleSize = 8; 
+0

那种作品,除了图像现在在活动的顶部附近被压扁了吗? – x10sion

+0

是的,因为inSampleSize返回一个较小的图像来节省内存,因此,质量会下滑 –

+0

有没有办法让它仍然显示在相同的大小,但质量稍低? – x10sion

0

这里是我通常用来计算的方法inSampleSize

private int calculateInSampleSize(BitmapFactory.Options opts, int reqWidth, int reqHeight) { 
    int outHeight = opts.outHeight; 
    int outWidth = opts.outWidth; 
    int inSampleSize = 1; 
    while (outHeight > reqHeight || outWidth > reqWidth) { 
     outHeight /= 2; 
     outWidth /= 2; 
     inSampleSize *= 2; 
    } 
    return inSampleSize; 
} 

如果你希望你的位图适合您的ImageView,您可以使用scaleType在XML这样的:

<ImageView 
    android:scaleType="centerCrop" 
    android:id="@+id/test_iv" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent"/> 

如果你不想自己对图像进行解码,您可能需要使用像Glide

+0

有没有办法让它仍然以相同的尺寸显示,但质量略低,因为我的图像以相当长的图像离开屏幕 – x10sion

0

一些第三方库有一个与我的代码出了问题(这是从Android的 自理)

它没有错(从某种意义上说它没有故障)。它正在做什么陈述。

任何人都不会有大的图像解码更好的办法,所以我不明白 的OOM

Ammm ..我不这样做,但是我可以告诉你,你可以进行更改,使这项工作。

用于计算下采样索引的条件存在问题。我会用你的问题给出的例子来解释它。

Configuration landscape 

XXHDPI qhd device with dimention 960x540 hence, 

    deviceWidth 960 deviceHeight 540 
    halfWidth 960 halfHeight 517 
    imgWidth 1920 imgHeight 1035 

设备宽度是必要的宽度在这里的话,

reqWidth 960 reqHeight 540  

您使用的条件是

while ((halfHeight/inSampleSize) >= reqHeight 
       && (halfWidth/inSampleSize) >= reqWidth) { 
//--------i tried a sample size of 2. was hoping 3 would work---------// 
     inSampleSize *= 3; 
     } 

如果我们简单地设置参数变得

while ((517/1) >= 540 
       && (960/1) >= 960) { 
//--------i tried a sample size of 2. was hoping 3 would work---------// 
     inSampleSize *= 3; 
     } 

正如你可以看到第一个条件不满足,因此虽然循环被打破并且inSampleSize保持为1,意味着图像不会被重新采样。这可能会导致OOM。

的想法是,当你走向更高的高宽比它会更容易获得给定条件OOM,

例如图像去, 尺寸为2160 x 1035的图像更有可能导致您的应用程序崩溃(注意:由于相同的原因,此图像不会重新采样)。

而且随着尺寸4320 X 1035的图像肯定会崩溃您的应用程序(注意:这不会重样要么)

也是如此的1035 X 4320(肖像的情况下)。

那么要改变什么? 条件应修改,使之做这样的事情,

Get the large side of image, down sample it until it fits adjacent device side 

我会让你来改变状况,你认为适合。

UPLDATE:

我想指出,在this答案的评论OP提到链接到一个要点这实际上表明你在找什么。它还通过将位图配置设置为每像素16位(RGB_888使用24)的RGB_565来减小给定位图的大小,从而进一步实现。

scaledBitmap = Bitmap.createBitmap(actualWidth, actualHeight, Bitmap.Config.RGB_565); 

请注意,这会降低图像的质量。

+0

你有没有ImageCompression的例子在我看到的要点? – x10sion

相关问题