android拍照的简单方式:调用已存在的camera应用
如果你的app中有要拍照的需求,有两种方式可以实现,一是直接调用已安装的app,二是自己写一个拍照界面。这篇文章讲解最简单的方式,直接调用已有的camera应用。其实绝大多数安卓手机都会有自带的camera应用。
获取camera权限
如果你的应用必须要用到拍照的功能,那么你需要在google play上将可以下载该应用的设备限制在拥有camera程序的设备中,为了表明你的应用依赖于camera程序,你需要在 manifest 文件中使用<uses-feature>
标签:
<manifest ... >
<uses-feature android:name="android.hardware.camera" />
...
</manifest ... >
而如果你的应用会用到拍照功能,但是不用也无关大碍的话,你可以给<uses-feature
>标签加上android:required="false"
,表明你的应用可以在没有camera的设备上使用,google play将允许那些没有装有camera的设备下载,但是这时你必须在自己的代码中判断一个设备是由可调用camera,如果没有camera,你应该关闭拍照功能,判断的方式是:
hasSystemFeature(PackageManager.FEATURE_CAMERA)
开始调用camera应用拍照
在安卓中调用其他activity是通过激发描述行为的intent来实现的,这一过程包含了三个方面,intent本省、调用外部activity、获得调用完成之后的返回值。
下面是通过intent来发出拍照请求的代码:
private void dispatchTakePictureIntent(int actionCode) {
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
startActivityForResult(takePictureIntent, actionCode);
}
通过上面几行简单的代码就能调用拍照程序了,但是如果设备中根本没有一个应用能处理该intent请求(MediaStore.ACTION_IMAGE_CAPTURE
),那么你的应用就会崩溃,为此,我们需要先判断设备中是否有能响应这个intent的app,代码如下:
public static boolean isIntentAvailable(Context context, String action) {
final PackageManager packageManager = context.getPackageManager();
final Intent intent = new Intent(action);
List<ResolveInfo> list =
packageManager.queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);
return list.size() > 0;
}
显示照片
但是你的目的可能不仅仅是拍照,而且还需要获得拍出的照片,然后对之进行某种操作。安卓的camera应用会在拍照完成之后返回一个intent给 onActivityResult()函数,该intent的extra部分包含了经过camera编码的图片的`Bitmap`,通过以下方式将该`Bitmap` 显示在imageview中:
private void handleSmallCameraPhoto(Intent intent) {
Bundle extras = intent.getExtras();
mImageBitmap = (Bitmap) extras.get("data");
mImageView.setImageBitmap(mImageBitmap);
}
注意,如果图片比较大,这个过程可能有点耗时。
保存照片
如果你提供了一个完整的文件路径,安卓的camera程序会自动保存一张原始尺寸的图片。你需要提供存储位置、文件名、目录。
下面是获得图片路径的一个简单方法,但是只适用于android2.2以上版本:
storageDir = new File(
Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_PICTURES
),
getAlbumName()
);
更早的版本需要你自己提供文件目录名:
storageDir = new File (
Environment.getExternalStorageDirectory()
+ PICTURES_DIR
+ getAlbumName()
);
注:PICTURES_DIR
其实就是 Pictures/
,这是外部存储系统上存储图片的标准位置。
设置照片的文件名
上面生成文件名都是通过系统环境的函数获得的,我们需要做的是为图片取一个名字,文件名最好是按照一定规则来生成,下面提供了一个生成文件名的方法:
private File createImageFile() throws IOException {
// Create an image file name
String timeStamp =
new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
String imageFileName = JPEG_FILE_PREFIX + timeStamp + "_";
File image = File.createTempFile(
imageFileName,
JPEG_FILE_SUFFIX,
getAlbumDir()
);
mCurrentPhotoPath = image.getAbsolutePath();
return image;
}
将该文件路径放入intent中
通过intent将文件的路径传递给camera程序:
File f = createImageFile();
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(f));
将图片添加进gallery
可能你自己很清楚照片放在什么地方,因为是你存的,但为了让其他人也能看到这张图片,我们需要让系统的Media Provider能访问它。通过如下方法可以将图片添加进media provider数据库中,这样gallery等应用就可以访问到这张图片。
private void galleryAddPic() {
Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
File f = new File(mCurrentPhotoPath);
Uri contentUri = Uri.fromFile(f);
mediaScanIntent.setData(contentUri);
this.sendBroadcast(mediaScanIntent);
}
编码图片
照出来的原始图片可能比较大,不适合内存吃紧的情况,我们需要将图片缩放以适合目标视图的大小,下面是代码:
private void setPic() {
// Get the dimensions of the View
int targetW = mImageView.getWidth();
int targetH = mImageView.getHeight();
// Get the dimensions of the bitmap
BitmapFactory.Options bmOptions = new BitmapFactory.Options();
bmOptions.inJustDecodeBounds = true;
BitmapFactory.decodeFile(mCurrentPhotoPath, bmOptions);
int photoW = bmOptions.outWidth;
int photoH = bmOptions.outHeight;
// Determine how much to scale down the image
int scaleFactor = Math.min(photoW/targetW, photoH/targetH);
// Decode the image file into a Bitmap sized to fill the View
bmOptions.inJustDecodeBounds = false;
bmOptions.inSampleSize = scaleFactor;
bmOptions.inPurgeable = true;
Bitmap bitmap = BitmapFactory.decodeFile(mCurrentPhotoPath, bmOptions);
mImageView.setImageBitmap(bitmap);
}