如果想要我们的APP具有拍照功能,有两种方式可以实现,一种是调用拍照APP,比如Android系统自带的Camera APP;另一种就是完全自己写,自己调用照相机的API,控制快门等,实现类似Camera APP的应用。第一种相对简单,第二种就比较复杂。如果我们的APP不是以拍照功能为主,我们就可以选择第一种简单的实现方式。下面就讲一讲第一种方式的重点知识。第二种方式暂时不讲。
如果APP有照相功能,首先要做的就是在AndroidManifest.xml
中添加如下声明:
<uses-feature android:name="android.hardware.camera" android:required="true" />
虽然这不是必须的,但是这是一种推荐的做法。声明了这个之后,如果某个手机设备不支持拍照功能,那么它就不能安装这个APP。如果想要它即使没有摄像头也能安装,那么可以将required
的值设置为false。这时候我们需要在代码中检测是否受摄像头,如果没有,需要禁用掉拍照模块。
if(getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA)){
photoBtn.setOnClickListener(this);
}else{
photoBtn.setVisibility(View.GONE);
}
调起第三方拍照APP拍照的代码如下:
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);
}
}
需要注意的是,在调用startActivityForResult()
方法之前需要先检查是否有第三方拍照的APP响应这个Intent,否则APP会崩溃。
由于一张照片通常比较大,至少2M,所以Android 系统只会在拍照的返回结果Intent中存入拍摄的照片的缩略图,不会返回完整尺寸的照片。缩略图以Bitmap对象存储在Intent的“data”字段,可以用来当作icon等。如下是处理缩略图的代码:
@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);
String desc = "缩略图信息:\n"+"w="+imageBitmap.getWidth()+"\nh="+imageBitmap.getHeight();
mDescTv.setText(desc);
}
}
我们如果想要获得拍摄的完整尺寸的照片,可以在发起拍照的Intent中传入要保存的照片的完整路径。
首先创建要保存的照片的临时文件:
private File createImageFile() throws IOException {
// 使用当前时间命名文件,避免冲突
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
String imageFileName = "JPEG_" + timeStamp + "_";
//存放在公共目录Pictures
File storageDir = Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_PICTURES);
File image = File.createTempFile(
imageFileName, /* prefix */
".jpg", /* suffix */
storageDir /* directory */
);
// 保存当前照片的完整路径,备用
mCurrentPhotoPath = image.getAbsolutePath();
return image;
}
然后在Intent中传入路径:
File photoFile = null;
try {
photoFile = createImageFile();
} catch (IOException e) {
e.printStackTrace();
}
if(photoFile != null){
//设置保存照片的路径
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(photoFile));
startActivityForResult(takePictureIntent, REQUEST_IMAGE_CAPTURE);
}
注意:如果指定了EXTRA_OUTPUT
,那么onActivityResult(int requestCode, int resultCode, Intent data)
的Intent data == null。
虽然照片存储在了公共目录Pictures下,但是我们使用其它图库APP查看手机图片时却找不到我们刚刚拍摄的照片。这是因为我们还没有将他们添加到MediaProvider。我们需要主动调起系统MediaScanner
,将照片添加到MediaProvider的数据库中。代码如下:
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);
}
我们是通过发送一个广播消息来通知MediaScanner将指定的文件加入到媒体库中,这样其他的APP就可以通过MediaProvider访问到我们拍摄的照片了。当然,如果我们的照片存储在APP私有目录下(getExternalFileDirs
),MediaScanner是没法扫描到的,上面的方法就没有作用了。
同样,我们可以调起第三方APP来录制视频。我们也可以使用EXTRA_OUTPUT
指定视频存储的位置。同时,在返回结果的Intent中通过getData
可以获得视频的URI。关键代码如下:
private void dispatchTakeVideoIntent() {
Intent takePictureIntent = new Intent(MediaStore.ACTION_VIDEO_CAPTURE);
if (takePictureIntent.resolveActivity(getPackageManager()) != null) {
File videoFile = null;
try {
videoFile = createMediaFile(".mp4");
} catch (IOException e) {
e.printStackTrace();
}
if(videoFile != null){
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(videoFile));
startActivityForResult(takePictureIntent, REQUEST_VIDEO_CAPTURE);
}
}
}
得到视频的URI后,我们可以通过VideoView
来播放视频。如下:
if(requestCode == REQUEST_VIDEO_CAPTURE){
addFileToMedia();
if (data == null) return;
Uri videoUri = data.getData();
Log.e("test", "data uri=>" + videoUri);
if (videoUri != null) {
mVideoView.setVideoURI(videoUri);
mVideoView.start();
}
}
以上就是拍照录像功能涉及到的一些比较重点的知识。