高分辨率背景图像在Android中提供性能问题

时间:2014-12-08 14:38:34

标签: android xml imageview image-resizing picasso

我希望有一个背景图片可以缩放以适应Android中的任何屏幕尺寸。图像是静态的,不需要滚动。我以4K分辨率制作了图像,以涵盖未来2 - 3年(2560 x 1600已经存在)平板电脑上可能出现的分辨率。该图像是JPG,文件大小为137KB。类似的分辨率图像似乎在Android Web浏览器中正常工作。为什么我在Android中遇到了很多问题(在三星Galaxy S3上,应该有足够的CPU / RAM来处理这样的图像)?我不觉得我做了什么与众不同的事情。

这会在XML布局中加载图像。图像当前存储在drawable-nodpi中。

<ImageView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:src="@drawable/logo_background"
    android:scaleType="centerCrop" />

为每种类别的屏幕分辨率制作不同尺寸的图像很困难,因为我无法找到有关每个类别中设备当前最大分辨率的信息最少的信息。

我想在各种片段之间反复使用相同的背景图像。有没有办法让图像重新调整一次到屏幕的宽度(最好是异步),然后每次加载调整大小的图像?这可以用毕加索来完成吗?

请不要给出像&#34这样的答案;当然,较大的图像会导致性能问题&#34;或者链接到Google支持的不同密度。这是一个真正的问题,随着屏幕分辨率不断提高,这将成为一个更大的问题。我很惊讶在ImageView类中尚未优化处理和调整大图像的大小,这让我觉得我做错了。

3 个答案:

答案 0 :(得分:2)

问题在于您尝试做的不是依赖SDK。通过拥有一个映像并且必须在运行时更改映像,您将在onDraw()中的UI线程上完成更多工作。

当然,你可以为特定大小创建一个Bitmap,但是为什么在你可以依赖SDK时这么复杂呢?

目前,您可以使用许多不同的文件夹来获取所需内容,然后将来可以将4k图像放入特定文件夹中。这样的事情可能有用:

抽拉-xhdpi 绘制,xxhdpi drawable-xlarge-xhdpi - 对于你想要完成的事情可能不够具体 drawable-sw600dp - 这允许您为屏幕宽度大于600dp的图像指定文件夹。此限定符可能对您的情况有所帮助,将来您将使用4k图像。

答案 1 :(得分:0)

你甚至不需要毕加索队友。在这里你得到了屏幕尺寸:

LinearLayout layout = (LinearLayout)findViewById(R.id.YOUR_VIEW_ID);
ViewTreeObserver vto = layout.getViewTreeObserver(); 
vto.addOnGlobalLayoutListener(new OnGlobalLayoutListener() { 
@Override 
public void onGlobalLayout() { 
    this.layout.getViewTreeObserver().removeGlobalOnLayoutListener(this); 
    int width  = layout.getMeasuredWidth();
    int height = layout.getMeasuredHeight(); 

} 
});

在这里,您可以使用新尺寸调整图片大小:

public Bitmap getResizedBitmap(Bitmap bm, int newHeight, int newWidth){
int width = bm.getWidth();
int height = bm.getHeight();
float scaleWidth = ((float) newWidth) / width;
float scaleHeight = ((float) newHeight) / height;
// create a matrix for the manipulation
Matrix matrix = new Matrix();
// resize the bit map
matrix.postScale(scaleWidth, scaleHeight);
// recreate the new Bitmap
Bitmap resizedBitmap = Bitmap.createBitmap(bm, 0, 0, width, height, matrix, false);
return resizedBitmap;
}

使用矩阵调整大小相对较快。尽管user1090347的回答是最好的做法。

答案 2 :(得分:0)

问题是android使用Bitmap将图像渲染到画布。这对我来说就像BMP图像格式。所以,你没有从JPG格式中获益,因为从jpg转换中丢失的所有信息都会永远丢失,无论如何你最终会完整地使用位图。大分辨率的问题是,你必须为每个像素寻址几个字节,不应用转换!特别是,较小的设备具有较低的存储级别作为较大的存储级因此,您必须根据设备屏幕大小和内存类别处理图像分辨率。

您可以使用这些辅助函数在运行时正确转换背景位图:

public void getScreenSizePixels(Resources resources, int widthHeightInPixels[/*2*/])
    {
        Configuration config = resources.getConfiguration();
        DisplayMetrics dm = resources.getDisplayMetrics();
        double screenWidthInPixels = (double)config.screenWidthDp * dm.density;
        double screenHeightInPixels = screenWidthInPixels * dm.heightPixels / dm.widthPixels;
        widthHeightInPixels[0] = (int)(screenWidthInPixels + .5);
        widthHeightInPixels[1] = (int)(screenHeightInPixels + .5);
    }

-

public static Bitmap getBitmap(byte[] imageAsBytes, int reqWidth, int reqHeight) {
    BitmapFactory.Options opt = new BitmapFactory.Options();
    opt.inJustDecodeBounds = true;
    BitmapFactory.decodeByteArray(
        imageAsBytes,
        0,
        imageAsBytes.length,
        opt);
    int width = opt.outWidth;
    int height = opt.outHeight;
    int scale = 1;
    while (reqWidth < (width / scale) || reqHeight < (height / scale)) {
      scale++;
    }
    //bitmap.recycle();
    opt.inJustDecodeBounds = false;
    opt.inSampleSize = scale;
    Bitmap bitmap = BitmapFactory.decodeByteArray(
        imageAsBytes,
        0,
        imageAsBytes.length,
        opt);
    return bitmap;
  }