Android简单拍照

camera

1、简单拍照

1.1请求camera的feature

1
2
3
4
<manifest ... >
<uses-feature android:name="android.hardware.camera" android:required="true" />
...
</manifest>

如果我们的app必须使用相机,required=”true”可以声明为true,这样做的话,Google Play不允许没有相机的设备下载此程度。如果我们没有声明,但是没有相机的用户下载了,我们可以使用 hasSystemFeature(PackageManager.FEATURE_CAMERA)).来判断。

1.2使用相机来拍照

1
2
3
4
5
6
7
8
static final int REQUEST_IMAGE_CAPTURE = 1;
private void dispatchTakePictureIntent() {
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
if (takePictureIntent.resolveActivity(getPackageManager()) != null) {
startActivityForResult(takePictureIntent, REQUEST_IMAGE_CAPTURE);
}
}

resolveActivity())返回的是第一个可以处理这个inten的请求的activity,如果是null的话,证明没有activity可以被使用(不一定是不能用,有可能是占用),所以做这个判断很有必要。

1.3获取缩略图

使用intent系统内置的data可以获取缩略图,示例代码

1
2
3
4
5
6
7
8
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == REQUEST_IMAGE_CAPTURE && resultCode == RESULT_OK) {
Bundle extras = data.getExtras();
Bitmap imageBitmap = (Bitmap) extras.get("data");
mImageView.setImageBitmap(imageBitmap);
}
}

这样获取的只是缩略图,我们要取得原图的话还需要一点操作

1.4获取原图

如果想保存完整图片的话,我们应该提供一个完整的文件用来存储相机拍摄的图片
一般来说,用户用设备摄像头捕捉到的任何照片都应该保存在公共外部存储设备上,以便所有应用都能访问这些照片。我们选择 getExternalStoragePublicDirectory())、 DIRECTORY_PICTURES提供的目录。
因为涉及存储,所以需要声明相关的权限

1
2
3
4
<manifest ...>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
...
</manifest>

但是,如果我们希望照片只保留到您的应用程序中,则可以使用 getExternalFilesDir())提供的目录。在Android 4.3和更低的版本中,写到这个目录也需要写外部存储权限。从Android 4.4开始,不再需要权限,因为其他应用程序无法访问该目录,我们可以通过添加maxSdkVersion属性来声明仅在较低版本的Android上只请求允许的权限。

1
2
3
4
5
<manifest ...>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
android:maxSdkVersion="18" />
...
</manifest>

我们通过 getExternalFilesDir()) 或者 getFilesDir())存储的文件会随着app卸载被一起删除

一旦确定了该文件的目录,就需要创建一个唯一的文件名,我们使用时间戳。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
String mCurrentPhotoPath;
private File createImageFile() throws IOException {
// Create an image file name
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
String imageFileName = "JPEG_" + timeStamp + "_";
File storageDir = getExternalFilesDir(Environment.DIRECTORY_PICTURES);
File image = File.createTempFile(
imageFileName, /* prefix */
".jpg", /* suffix */
storageDir /* directory */
);
// Save a file: path for use with ACTION_VIEW intents
mCurrentPhotoPath = image.getAbsolutePath();
return image;
}

完整的流程如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
static final int REQUEST_TAKE_PHOTO = 1;
private void dispatchTakePictureIntent() {
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
// Ensure that there's a camera activity to handle the intent
if (takePictureIntent.resolveActivity(getPackageManager()) != null) {
// Create the File where the photo should go
File photoFile = null;
try {
photoFile = createImageFile();
} catch (IOException ex) {
// Error occurred while creating the File
...
}
// Continue only if the File was successfully created
if (photoFile != null) {
Uri photoURI = FileProvider.getUriForFile(this,
"com.example.android.fileprovider",
photoFile);
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI);
startActivityForResult(takePictureIntent, REQUEST_TAKE_PHOTO);
}
}
}

对于7.0或者更高,我们需要使用getUriForFile(Context, String, File),如果用的是这样的 file:// URI ,则会返回一个FileUriExposedException异常。因此,我们要使用 FileProvider.

provider属于四大组件,需要在清单文件声明

1
2
3
4
5
6
7
8
9
10
11
12
13
<application>
...
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="com.example.android.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths"></meta-data>
</provider>
...
</application>

确保getUriForFile的第二个参数和android:authorities填写的一致。

创建file_paths xml,内容如下

1
2
3
4
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path name="my_images" path="Android/data/com.example.package.name/files/Pictures" />
</paths>