使用相机intent,我们就可以成功拍摄现场照片并保存了。
有了照片,接下来就是找到并加载它,然后展示给用户看。在南昌APP开发的技术实现上,这需要加载照片到大小合适的Bitmap对象中。要从文件生成Bitmap对象,我们需要BitmapFactory类:
Bitmap bitmap = BitmapFactory.decodeFile(mPhotoFile.getPath());
看到这里,有没有感觉不对劲?肯定有的。问题在于:介绍Bitmap时,我们提到“大小合适”。Bitmap是个简单对象,它只存储实际像素数据。也就是说,即使原始照片已压缩过,但存入Bitmap对象时,文件并不会同样压缩。因此,16万像素24位已压缩为5Mb大小的JPG照片文件,一旦载入Bitmap对象,就会立即膨胀至48Mb大小!
这其实个问题是可以设法解决的,但需要手工缩放位图照片。具体做法就是,首先确认文件到底有多大,然后考虑按照给定区域大小合理缩放文件。最后,重新读取缩放后的文件,创建Bitmap对象。
创建名为PictureUtils.java的新类,并在其中添加getScaledBitmap(String, int, int)缩放方法,如下代码清单所示。
创建getScaledBitmap(...)方法(PictureUtils.java)
public class PictureUtils {
public static Bitmap getScaledBitmap(String path, int destWidth, int destHeight) {
// Read in the dimensions of the image on disk
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(path, options);
float srcWidth = options.outWidth;
float srcHeight = options.outHeight;
// Figure out how much to scale down by
int inSampleSize = 1;
if (srcHeight > destHeight || srcWidth > destWidth) {
if (srcWidth > srcHeight) {
inSampleSize = Math.round(srcHeight / destHeight);
} else {
inSampleSize = Math.round(srcWidth / destWidth);
}
}
options = new BitmapFactory.Options();
options.inSampleSize = inSampleSize;
// Read in and create final bitmap
return BitmapFactory.decodeFile(path, options);
}
}
上述方法中,inSampleSize值很关键。它决定着缩略图像素的大小。假设这个值是1的话,就表明缩略图和原始照片的水平像素大小一样。如果是2的话,它们的水平像素比就是1∶2。因此,inSampleSize值为2时,缩略图的像素数就是原始文件的四分之一。
问题总是接踵而来,解决了缩放问题,又冒出了新问题:fragment刚启动时,PhotoView
究竟有多大无人知道。onCreate(...)、onStart()和onResume()方法启动后,才会有实例化布局出现。也就在此时,显示在屏幕上的视图才会有大小尺寸。这也是出现新问题的原因。
解决方案有两个:要么等布局实例化完成并显示,要么干脆使用保守估算值。特定条件下,尽管估算比较主观,但确实是一个切实可行的办法。再添加一个getScaledBitmap(String,Activity)静态Bitmap估算方法,如下代码所示。
编写合理的缩放方法(PictureUtils.java)
public class PictureUtils {
public static Bitmap getScaledBitmap(String path, Activity activity) {
Point size = new Point();
activity.getWindowManager().getDefaultDisplay()
.getSize(size);
return getScaledBitmap(path, size.x, size.y);
}
...
该方法先确认屏幕的尺寸,然后按此缩放图像。这样,就能保证载入的ImageView永远不会过大。看到没有,无论如何,这是一个比较保守的估算有时就是能解决问题。
接下来,为把Bitmap载入ImageView。在CrimeFragment.java中,添加刷新mPhotoView的方法,如下代码清单所示。
更新mPhotoView(CrimeFragment.java)
...
private String getCrimeReport() {
...
}
private void updatePhotoView() {
if (mPhotoFile == null || !mPhotoFile.exists()) {
mPhotoView.setImageDrawable(null);
} else {
Bitmap bitmap = PictureUtils.getScaledBitmap(
mPhotoFile.getPath(), getActivity());
mPhotoView.setImageBitmap(bitmap);
}
}
}
然后,分别在onCreateView(...)和onActivityResult(...)方法中调用updatePhotoView()
方法,如下代码清单所示。
调用updatePhotoView()方法(CrimeFragment.java)
mPhotoButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
startActivityForResult(captureImage, REQUEST_PHOTO);
}
});
mPhotoView = (ImageView) v.findViewById(R.id.crime_photo);
updatePhotoView();
return v;
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (resultCode != Activity.RESULT_OK) {
return;
}
if (requestCode == REQUEST_DATE) {
...
} else if (requestCode == REQUEST_CONTACT && data != null) {
...
} else if (requestCode == REQUEST_PHOTO) {
updatePhotoView();
}
}
再次运行应用,这样就可以看到已拍照片的缩略图了。