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



我想要一个可以缩放以适应Android中任何屏幕尺寸的背景图像。图像是静态的,不需要滚动。我以 4K 分辨率制作了图像,以涵盖未来 2-3 年内平板电脑上可能存在的分辨率(2560 x 1600 已经存在(。该图像是文件大小为 137KB 的 JPG。类似的分辨率图像似乎在Android网络浏览器中工作正常。为什么我在Android中速度变慢(在三星Galaxy S3上,它应该有足够的CPU/RAM来处理这样的图像(?我不觉得我做了任何不寻常的事情。

这将在 XML 布局中加载图像。图像当前存储在可绘制的 nodpi 中。

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

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

我想在各种片段之间一次又一次地使用相同的背景图像。有没有办法将图像大小调整一次到屏幕宽度(最好是异步(,然后每次加载调整后的图像?这能用毕加索做吗?

请不要给出诸如"当然较大的图像会导致性能问题"之类的答案,也不要将我链接到Google的支持不同密度。这是一个真正的问题,随着屏幕分辨率的不断提高,这个问题将变得更加严重。我很惊讶在 ImageView 类中处理和调整大图像大小尚未优化,这让我觉得我做错了什么。

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

当然,您可以为特定大小创建位图,但是当您可以依赖SDK时,为什么要做如此复杂的工作呢?

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

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

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

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

使用矩阵调整大小相对较快。尽管user1090347s的答案将是最佳做法。

问题是 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;
  }

最新更新