加载并且显示一幅图像对内存使用情况具有显著的影响。例如,HTC G1电话带有一个320万像素的摄像头。320万像素的摄像头通常会捕获2048 X 1536像素的图像。显示如此大小的32位图像将需要超过100663kb或大约13MB的内存。虽然我们的应用程序不一定会因此耗尽内存,但是这肯定会使得内存更加的容易耗尽。
Android提供了一个名为BitmapFactory的应用程序类,该程序类提供了一系列的静态方法,允许通过各种来源加载Bitmap图像。针对我们的需求,将从文件加载图像,并且在最初的活动中显示它。幸运的是,BitmapFactory中的可用的方法将会调用BitmapFactory.Options类,这使得我们能够定义如何将Bitmap读入内存。具体而言,当加载图像时,可以设置BitmapFactory应该使用的采样大小。在BitmapFactory.Options中指定inSamlpeSize参数,这将表明一旦加载时结果Bitmap图像所占的比例。例如,在这里将inSamlpeSize设置为8,这将产生一幅大小是原始图像大小1/8的图像。
1 BitmapFactory.Options bmpBitmapFactoryOptions=new BitmapFactory.Options(); 2 bmpBitmapFactoryOptions.inSampleSize=8; 3 Bitmap bmp=BitmapFactory.decodeFile(imageFilePath, bmpBitmapFactoryOptions); 4 imv.setImageBitmap(bmp);
这是一个快速加载大图像的方法,但是没有真正的考虑到图像的原始大小,也没有考虑到屏幕的大小。最好能够将图像缩放到刚好适应屏幕。
下面的片段演示了如何使用显示维度来确定在加载图像时应该发生的减采样量。当使用这个方法时,应确保该图像尽可能多的填充显示范围。但如果该图像只是要在任何一个维度中显示100个像素,那么应该使用这个值而不是维度,可以通过以下的方式获得该值。
1 Display currentDisplay=getWindowManager().getDefaultDisplay(); 2 Point point=new Point(); 3 currentDisplay.getSize(point); 4 int dw=point.x; 5 int dh=point.y;
为了确定图像的所有尺寸(用于计算),我们使用了BitmapFactory和BitmapFactory.Options,并将bmpBitmapFactoryOptions.inJustDecodeBounds设置为true。这将通知BitmapFactory类只需返回该图像的范围,而无需尝试解码图像本身。当使用此方法时,bmpBitmapFactoryOptions.outHeight和bmpBitmapFactoryOptions.outWidth变量将会被赋值。
1 //加载图像的尺寸而非图像的本身 2 BitmapFactory.Options bmpBitmapFactoryOptions=new BitmapFactory.Options(); 3 bmpBitmapFactoryOptions.inJustDecodeBounds=true; 4 Bitmap bmp=BitmapFactory.decodeFile(imageFilePath, bmpBitmapFactoryOptions); 5 int heightRatio=(int)Math.ceil(bmpBitmapFactoryOptions.outHeight/(float)dh); 6 int widthRatio=(int)Math.ceil(bmpBitmapFactoryOptions.outWidth/(float)dw);
简单的将图像的尺寸除以显示的尺寸 将获得显示的比率。然后,可以选择是否使用高度比率或者宽度比率,这取决于他们当中谁更大。只需将这个比率作为bmpBitmapFactoryOptions.inSampleSize变量,这将产生一幅应该加载到内存的图像,其尺寸接近于我们在这种情况下所需的尺寸,也接近于显示本身的尺寸。
1 //两个比率都大于1时 2 //那么图像的一条边将大于屏幕 3 if(heightRatio>1&&widthRatio>1){ 4 if(heightRatio>widthRatio){//如果高度的比率更大 则根据高度来缩放 5 bmpBitmapFactoryOptions.inSampleSize=heightRatio; 6 }else{//如果宽度的比率更大 则根据宽度来缩放 7 bmpBitmapFactoryOptions.inSampleSize=widthRatio; 8 } 9 } 10 //开始真正的解码 11 bmpBitmapFactoryOptions.inJustDecodeBounds=false; 12 bmp=BitmapFactory.decodeFile(imageFilePath, bmpBitmapFactoryOptions);
下面试通过一个意图使用内置的摄像头并显示结果图片的完整示例代码。
1 package com.bluemobi.nthm.showversion; 2 3 import java.io.File; 4 5 import android.app.Activity; 6 import android.content.Intent; 7 import android.graphics.Bitmap; 8 import android.graphics.BitmapFactory; 9 import android.graphics.Point; 10 import android.net.Uri; 11 import android.os.Bundle; 12 import android.os.Environment; 13 import android.view.Display; 14 import android.widget.ImageView; 15 16 public class SizedCameraIntent extends Activity { 17 private final int CAMERA_RESULT=0; 18 private ImageView imv; 19 String imageFilePath=""; 20 @Override 21 protected void onCreate(Bundle savedInstanceState) { 22 super.onCreate(savedInstanceState); 23 setContentView(R.layout.cameraintentactivity); 24 imageFilePath=Environment.getExternalStorageDirectory().getAbsolutePath()+"myfavoritepicture.jpg"; 25 File imageFile=new File(imageFilePath); 26 Uri imageFileUri=Uri.fromFile(imageFile); 27 28 Intent i=new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE); 29 i.putExtra(android.provider.MediaStore.EXTRA_OUTPUT, imageFileUri); 30 startActivityForResult(i, CAMERA_RESULT); 31 } 32 @Override 33 protected void onActivityResult(int requestCode, int resultCode, Intent data) { 34 super.onActivityResult(requestCode, resultCode, data); 35 if(resultCode==RESULT_OK){ 36 //获取ImageView引用 37 imv=(ImageView) findViewById(R.id.ReturnedImageView); 38 Display currentDisplay=getWindowManager().getDefaultDisplay(); 39 Point point=new Point(); 40 currentDisplay.getSize(point); 41 int dw=point.x; 42 int dh=point.y; 43 //加载图像的尺寸而非图像的本身 44 BitmapFactory.Options bmpBitmapFactoryOptions=new BitmapFactory.Options(); 45 bmpBitmapFactoryOptions.inJustDecodeBounds=true; 46 Bitmap bmp=BitmapFactory.decodeFile(imageFilePath, bmpBitmapFactoryOptions); 47 int heightRatio=(int)Math.ceil(bmpBitmapFactoryOptions.outHeight/(float)dh); 48 int widthRatio=(int)Math.ceil(bmpBitmapFactoryOptions.outWidth/(float)dw); 49 //两个比率都大于1时 50 //那么图像的一条边将大于屏幕 51 if(heightRatio>1&&widthRatio>1){ 52 if(heightRatio>widthRatio){//如果高度的比率更大 则根据高度来缩放 53 bmpBitmapFactoryOptions.inSampleSize=heightRatio; 54 }else{//如果宽度的比率更大 则根据宽度来缩放 55 bmpBitmapFactoryOptions.inSampleSize=widthRatio; 56 } 57 } 58 //开始真正的解码 59 bmpBitmapFactoryOptions.inJustDecodeBounds=false; 60 bmp=BitmapFactory.decodeFile(imageFilePath, bmpBitmapFactoryOptions); 61 //显示图像 62 imv.setImageBitmap(bmp); 63 } 64 } 65 }
上述代码需要下列的layout/sizecameraintentactivity.xml文件:
1 <?xml version="1.0" encoding="utf-8"?> 2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 3 android:layout_width="match_parent" 4 android:layout_height="match_parent" 5 android:orientation="vertical" > 6 7 <ImageView 8 android:id="@+id/ReturnedImageView" 9 android:layout_width="wrap_content" 10 android:layout_height="wrap_content" 11 android:contentDescription="@string/about_us"/> 12 13 </LinearLayout>