一般来说,在android中对图片进行缩放,我们使用以下的代码:
public Bitmap resizeImage(Bitmap bitmap, int w, int h) { Bitmap BitmapOrg = bitmap; int width = BitmapOrg.getWidth(); int height = BitmapOrg.getHeight(); int newWidth = w; int newHeight = h; float scaleWidth = ((float) newWidth) / width; float scaleHeight = ((float) newHeight) / height; Matrix matrix = new Matrix(); matrix.postScale(scaleWidth, scaleHeight); Bitmap resizedBitmap = Bitmap.createBitmap(BitmapOrg, 0, 0, width, height, matrix, true); return resizedBitmap; }
1、我们先要从磁盘上先将图片加载到内存,然后才能对图片进行缩放,在移动设备上对内存的要求比较高,这在一定程度上降级了性能。
2、我们使用Bitmap.createBitmap这个方法进行缩放,使用的是Java层面的方法来缩放,我们知道Java层面对图片,视频等进行处理是有性能损失的。
如果只有一两张图片,用上面的方法进行缩放是没有问题的,如果是大量的图片或者是图片很大,就会出现明显降低性能,甚至出现OOM的异常,OOM的异常是必须要处理的。
下面给出优化方案,优化我们也是基于上面两点问题给出的。一次性从磁盘上读取并缩放,而且这个缩放实在Native层,能够显著提高效率,代码如下:
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); try { BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; BitmapFactory.decodeStream(getAssets().open("g_b090.jpg"), null, options); int targetDensity = getResources().getDisplayMetrics().densityDpi; DisplayMetrics dm = new DisplayMetrics(); getWindowManager().getDefaultDisplay().getMetrics(dm); int x = dm.widthPixels; int y = dm.heightPixels; options.inSampleSize = calculateInSampleSize(options, x, y); double xSScale = ((double)options.outWidth) / ((double)x); double ySScale = ((double)options.outHeight) / ((double)y); double startScale = xSScale > ySScale ? xSScale : ySScale; options.inScaled = true; options.inDensity = (int) (targetDensity*startScale); options.inTargetDensity = targetDensity; options.inJustDecodeBounds = false; Bitmap bitmap = BitmapFactory.decodeStream(getAssets().open("g_b090.jpg"), null, options); } catch (IOException e) { e.printStackTrace(); } }
public 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) { inSampleSize *= 2; } } return inSampleSize; }