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" />