Android系统的多媒体功能使用的是MediaStore类,这个类是Android多媒体数据库的封装类。无论我们是调用多媒体功能发送的intent,data,extra等,还是从多媒体数据库存取数据,都要通过这个类。
比如,我们要调用拍照功能,需要发送如下intent:
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
startActivityForResult(intent, IMAGE_REQUEST_CODE);
其中,MediaStore.ACTION_IMAGE_CAPTURE是调用拍照功能的action,startActivityForResult是启动相机拍照并获取结果。
使用相机拍照后,获取结果的处理如下:
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == Activity.RESULT_OK) {
switch (requestCode) {
case IMAGE_REQUEST_CODE:
Uri uri = data.getData();
if (null == uri) {
Bundle bundle = data.getExtras();
if (null != bundle) {
Bitmap bitmap = (Bitmap) bundle.get("data");
// MediaStore.Images.Media.insertImage(getContentResolver(),
// bitmap, "title", "description");
mImage.setImageBitmap(bitmap);
}
} else {
Log.d(TAG, "uri:" + uri.toString());
}
break;
}
}
}
不同手机中的相机处理照片的获取方式是不同的。方式有两种:
1、有的能够取到照片的Uri,然后我们可以直接用Uri获取到照片;
2、有的不能取到Uri,即此时的Uri为null,这时我们可以通过extra中的bundle,通过bundle.get("data"),将图片内容取出来。这时先将相机返回的数据转换成Bitmap图片格式,然后存储到多媒体数据库表中,并通过mImage.setImageBitmap(bitmap)方法显示到界面上,其中mImage是一个ImageView。
以上的方法是先调用拍照,然后通过相机程序拍照后返回的缩略图来显示。缺点是有时可能得不到原图的uri路径。因为不同手机的相机功能实现可能各异,导致支持的结果也不一样。就拿android Camera源码来看,采用以上方法就获取不到图片的Uri。
android Camera源码中执行处理拍照并返回的类是Camera.java。里面有这样一段代码,用来处理拍照后,并确认后所执行的内容:
private void doAttach() {
if (mPausing) {
return;
}
byte[] data = mJpegImageData;
if (mCropValue == null) {
// First handle the no crop case -- just return the value. If the
// caller specifies a "save uri" then write the data to it's
// stream. Otherwise, pass back a scaled down version of the bitmap
// directly in the extras.
if (mSaveUri != null) {
OutputStream outputStream = null;
try {
outputStream = mContentResolver.openOutputStream(mSaveUri);
outputStream.write(data);
outputStream.close();
setResultEx(RESULT_OK);
finish();
} catch (IOException ex) {
// ignore exception
} finally {
Util.closeSilently(outputStream);
}
} else {
int orientation = Exif.getOrientation(data);
Bitmap bitmap = Util.makeBitmap(data, 50 * 1024);
bitmap = Util.rotate(bitmap, orientation);
setResultEx(RESULT_OK,
new Intent("inline-data").putExtra("data", bitmap));
finish();
}
} else {
// Save the image to a temp file and invoke the cropper
Uri tempUri = null;
FileOutputStream tempStream = null;
try {
File path = getFileStreamPath(sTempCropFilename);
path.delete();
tempStream = openFileOutput(sTempCropFilename, 0);
tempStream.write(data);
tempStream.close();
tempUri = Uri.fromFile(path);
} catch (FileNotFoundException ex) {
setResultEx(Activity.RESULT_CANCELED);
finish();
return;
} catch (IOException ex) {
setResultEx(Activity.RESULT_CANCELED);
finish();
return;
} finally {
Util.closeSilently(tempStream);
}
Bundle newExtras = new Bundle();
if (mCropValue.equals("circle")) {
newExtras.putString("circleCrop", "true");
}
if (mSaveUri != null) {
newExtras.putParcelable(MediaStore.EXTRA_OUTPUT, mSaveUri);
} else {
newExtras.putBoolean("return-data", true);
}
Intent cropIntent = new Intent("com.android.camera.action.CROP");
cropIntent.setData(tempUri);
cropIntent.putExtras(newExtras);
startActivityForResult(cropIntent, CROP_MSG);
}
}
其中,mSaveUri就是前一个Activity发来的intent中的key为MediaStore.EXTRA_OUTPUT的extra值。mSaveUri获取代码如下:
private void setupCaptureParams() {
Bundle myExtras = getIntent().getExtras();
if (myExtras != null) {
mSaveUri = (Uri) myExtras.getParcelable(MediaStore.EXTRA_OUTPUT);
mCropValue = myExtras.getString("crop");
}
}
从上面的两段代码可以看出,当mSaveUri不为null时,即前一个应用程序传的intent包含key为MediaStore.EXTRA_OUTPUT的extra值时,相机程序会将拍出的照片保存本地存储,然后返回的值不包括intent;当mSaveUri为null时,相机程序会将拍出的照片转成bitmap通过intent返回给前一个调用的Activity。
我们的需求是既要保存到本地存储,又要获取到bitmap用以展示。因此,我采用了以下做法。
private final static int IMAGE_REQUEST_CODE = 1;
private Uri mPhotoUri;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
ContentValues values = new ContentValues();
mPhotoUri = getContentResolver().insert(
MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
intent.putExtra(MediaStore.EXTRA_OUTPUT, mPhotoUri);
startActivityForResult(intent, IMAGE_REQUEST_CODE);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == Activity.RESULT_OK) {
switch (requestCode) {
case IMAGE_REQUEST_CODE:
Bitmap bitmap = getBitmapFromUri();
//show bitmap
}
}
}
private Bitmap getBitmapFromUri() {
try {
Bitmap bitmap = MediaStore.Images.Media.getBitmap(getContentResolver(), mPhotoUri);
return bitmap;
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
这种做法是:
1、获取到图片的uri;
2、将该uri通过intent的extra传递给相机程序,以便保存照片到本地;
3、在onActivityResult回调中,获取到resultCode为Activity.RESULT_OK时,采用之前获得的uri来取出相应照片的缩略图bitmap以共展示。
其中需要注意,一般照片都是存储在sdcard/DCIM目录下,也就是外部存储。所以需要以下权限:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />