name="android.permission.ACCESS_FINE_LOCATION"/>
调用系统相机
你的应用可以通过发送一个Intent到系统相机应用来实现抓取一张照片或者一段视频剪辑,然后将它们返回给你的应用。
使用cameraintent调用系统相机流程如下:
(1)ComposeaCameraIntent-创建一个Intent请求用来拍照或者录像,有关的Intent类型如下:
MediaStore.ACTION_IMAGE_CAPTURE-该Intentaction类型用于请求系统相机拍照。
MediaStore.ACTION_VIDEO_CAPTURE-该Intentaction类型用于请求系统相机录像。
(2)StarttheCameraIntent-调用activity的startActivityForResult()方法来发送cameraintent请求拍照或者录像,当发送cameraintent以后,当前应用会跳转到系统相机应用app界面,让用户可以拍照或者录像。
(3)ReceivetheIntentResult-在你的应用中实现onActivityResult()回调方法去接收来自系统相机的拍摄结果。
该方法在用户完成拍照或者录像以后由系统调用。
系统拍照
代码如下,按上面的三步走:
button1.setOnClickListener(newView.OnClickListener(){
@Override
publicvoidonClick(Viewv){
Intentintent=newIntent(MediaStore.ACTION_IMAGE_CAPTURE);
startActivityForResult(intent,CAPTURE_IMAGE_ACTIVITY_REQUEST_CODE);
}
});
...
@Override
protectedvoidonActivityResult(intrequestCode,intresultCode,Intentdata){
super.onActivityResult(requestCode,resultCode,data);
/**
*通过data取得数据
*/
if(requestCode==CAPTURE_IMAGE_ACTIVITY_REQUEST_CODE){
Bundleextras=data.getExtras();
Bitmapbitmap=(Bitmap)extras.get("data");
image.setImageBitmap(bitmap);
}
}
但是,现在手机像素这么高,万一图片特别大呢,会不会data过大而FC呢?
放心,Android早就考虑到了,所以,data里面压根就不是完整的图片,它只是一张缩略图。
所以,我们需要获取到拍摄的原图,就不能使用这种方法。
但是我们可以这样做,我们可以指定MediaStore类的一个EXTRA_OUTPUT来指定拍摄图像保存的位置,相当于建立一个临时文件。
在onActivityResult中,我们不使用data来获取图像,而是直接去读这个临时文件即可。
如果自己代码指定了保存图片的uri,data里面就不会保存数据。
button1.setOnClickListener(newView.OnClickListener(){
@Override
publicvoidonClick(Viewv){
Intentintent=newIntent(MediaStore.ACTION_IMAGE_CAPTURE);
UrifileUri=getOutputMediaFileUri(MEDIA_TYPE_IMAGE);
intent.putExtra(MediaStore.EXTRA_OUTPUT,fileUri);
startActivityForResult(intent,CAPTURE_IMAGE_ACTIVITY_REQUEST_CODE);
}
});
...
@Override
protectedvoidonActivityResult(intrequestCode,intresultCode,Intentdata){
/**
*通过存储Uri取得数据
*/
if(requestCode==CAPTURE_IMAGE_ACTIVITY_REQUEST_CODE){
if(resultCode==RESULT_OK){
image.setImageURI(getOutputMediaFileUri(MEDIA_TYPE_IMAGE));
}
}
}
这样我们就可以获取到完整的拍摄图片了。
后面你可以让图像显示出来。
下面来看看保存多媒体文件:
拍照或者录像生成的多媒体文件需要保存到手机存储目录中(SDCard),所以在应用中必须有往手机中写文件的权限。
一般可以有多种本地路径来保存多媒体文件,但是主要有如下两种常用的路径:
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES)
该方法返回一个标准的外部存储路径去保存照片和视频。
这个路径是公共的,所以其他应用也可以访问,修改,删除该路径下的照片和视频,如果你的应用被卸载了,媒体文件依然存在本地储存中。
为了避免和其他多媒体文件混淆,你应该在公共目录下创建一个子目录来保存你自己应用中的多媒体数据。
Context.getExternalFilesDir(Environment.DIRECTORY_PICTURES)
该方法返回一个标准的,唯独当前应用自己可见的路径去保存照片和视频。
如果该应用被卸载,在该目录下的所有多媒体数据将会被移除。
但是有一个好处就是其他应用无法去访问,修改,删除该路径下的文件。
如下示例代码演示如何创建一个路径用来保存照片和视频:
publicstaticfinalintMEDIA_TYPE_IMAGE=1;
publicstaticfinalintMEDIA_TYPE_VIDEO=2;
/**CreateafileUriforsavinganimageorvideo*/
privatestaticUrigetOutputMediaFileUri(inttype){
returnUri.fromFile(getOutputMediaFile(type));
}
/**CreateaFileforsavinganimageorvideo*/
privatestaticFilegetOutputMediaFile(inttype){
FilemediaStorageDir=newFile(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES),"WatsonCamera");
if(!
mediaStorageDir.exists()){
if(!
mediaStorageDir.mkdirs()){
returnnull;
}
}
FilemediaFile;
if(type==MEDIA_TYPE_IMAGE){
mediaFile=newFile(mediaStorageDir.getPath()+File.separator+"IMG_watson.jpg");
}elseif(type==MEDIA_TYPE_VIDEO){
mediaFile=newFile(mediaStorageDir.getPath()+File.separator+"VID_watson.mp4");
}else{
returnnull;
}
returnmediaFile;
}
系统录像
发送Intent录像携带的外部数据extra的信息如下:
MediaStore.EXTRA_OUTPUT
该关键字和拍照使用的关键字一样,意思就是制定一个路径和文件名来构建一个Uri对象来保存录像结果。
MediaStore.EXTRA_VIDEO_QUALITY
该关键字用于指定拍摄的录像质量,参数0表示低质量,参数1表示高质量。
MediaStore.EXTRA_DURATION_LIMIT
该关键之用于指定拍摄的录像的时间限制,单位是秒。
MediaStore.EXTRA_SIZE_LIMIT
该关键字用于指定拍摄的录像文件大小限制,单位值byte。
代码如下,按上面的三步走:
button2.setOnClickListener(newView.OnClickListener(){
@Override
publicvoidonClick(Viewv){
Intentintent=newIntent(MediaStore.ACTION_VIDEO_CAPTURE);
UrifileUri=getOutputMediaFileUri(MEDIA_TYPE_VIDEO);
intent.putExtra(MediaStore.EXTRA_OUTPUT,fileUri);
intent.putExtra(MediaStore.EXTRA_VIDEO_QUALITY,1);
startActivityForResult(intent,CAPTURE_VIDEO_ACTIVITY_REQUEST_CODE);
}
});
...
@Override
protectedvoidonActivityResult(intrequestCode,intresultCode,Intentdata){
if(requestCode==CAPTURE_IMAGE_ACTIVITY_REQUEST_CODE){
if(resultCode==RESULT_OK){
image.setVisibility(View.VISIBLE);
video.setVisibility(View.GONE);
image.setImageURI(getOutputMediaFileUri(MEDIA_TYPE_IMAGE));
}
}elseif(requestCode==CAPTURE_VIDEO_ACTIVITY_REQUEST_CODE){
if(resultCode==RESULT_OK){
video.setVisibility(View.VISIBLE);
image.setVisibility(View.GONE);
video.setVideoURI(getOutputMediaFileUri(MEDIA_TYPE_VIDEO));
video.setOnPreparedListener(newMediaPlayer.OnPreparedListener(){
@Override
publicvoidonPrepared(MediaPlayermp){
video.start();
}
});
video.setOnCompletionListener(newMediaPlayer.OnCompletionListener(){
@Override
publicvoidonCompletion(MediaPlayermp){
if(null!
=video){
video.stopPlayback();
}
}
});
}
}
}
自定义相机
创建一个自定义的相机app基本遵循如下步骤:
检测和访问相机:
首先代码检测该设备相机是否存在,如果存在才能请求访问设备相机。
创建一个预览来显示相机图像:
在你的布局中使用SurfaceView控件,然后在代码中继承SurfaceHolder.Callback接口并且实现接口中的方法来显示来自相机的图像信息。
设置相机基本参数:
根据需求设置相机预览尺寸,图片大小,预览方向,图片方向等。
设置拍照录像监听:
当用户按下按钮时调用Camera.takePicture()或者MediaRecorder.start()来进行拍照或录像。
文件保存:
当拍照结束或者录像视频结束时,需要开启一个后台线程去保存图片或者视频文件。
释放相机资源:
Camera硬件是一个共享资源,所以你必须小心的编写你的应用代码来管理相机资源。
一般在Activity的生命周期的onResume中开启相机,在onPause中释放相机。
注意:
当你不在使用相机资源时,记得调用Camera.release()方法来释放相机资源,否则其他应用甚至你自己的应用再次请求访问设备相机时会失败,并且crash。
检测相机硬件是否存在
一般情况,我们会在运行代码时检测该设备是否有相机硬件,如果有相机硬件,才进一步去访问相机,如下是检测相机硬件是否存在是代码示例:
/**Checkifthisdevicehasacamera*/
privatebooleancheckCameraHardware(Contextcontext){
if(context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA)){
returntrue;
}else{
returnfalse;
}
}
Android设备可以有多个相机硬件,现在一般手机都是前后两个camera,因此我们在Android2.3以后也可以使用Camera.getNumberOfCameras()方法来获得当前设备camera个数来判断相机硬件是否存在。
创建Camera预览
Camera预览布局文件:
xmlversion="1.0"encoding="utf-8"?
>
android="
android:
layout_width="match_parent"
android:
layout_height="match_parent"
android:
orientation="vertical">
android:
id="@+id/record_navigation_bar"
android:
layout_width="match_parent"
android:
layout_height="48dp"
android:
background="#F8F8F8">
android:
id="@+id/record_act_back"
android:
layout_width="25dp"
android:
layout_height="31dp"
android:
layout_centerVertical="true"
android:
layout_marginLeft="10dp"
android:
layout_marginRight="10dp"
android:
src="@drawable/icon_ll_back"/>
android:
id="@+id/camera_preview"
android:
layout_width="match_parent"
android:
layout_height="fill_parent"
android:
layout_above="@+id/record_bottom_bar"
android:
layout_below="@+id/record_navigation_bar"/>
android:
id="@+id/record_bottom_bar"
android:
layout_width="match_parent"
android:
layout_height="60dp"
android:
layout_alignParentBottom="true"
android:
background="@drawable/recording_bottom_bar_bg_interview">
android:
layout_width="wrap_content"
android:
layout_height="30dp"
android:
layout_alignParentRight="true"
android:
layout_below="@+id/record_navigation_bar"
android:
layout_marginRight="10dp"
android:
layout_marginTop="10dp"
android:
gravity="center_vertical">
android:
id="@+id/record_video_tip"
android:
layout_width="15dp"
android:
layout_height="15dp"
android:
layout_marginRight="10dp"
android:
background="@drawable/record_video_tip"/>
android:
id="@+id/record_video_time"
android:
layout_width="wrap_content"
android:
layout_height="30dp"
android:
layout_marginRight="10dp"
android:
gravity="center_vertical"
android:
text="00:
00"
android:
textColor="@android:
color/white"
android:
textSize="17sp"/>
然后,我们创建一个Activity,用来展示Camera的预览,那么在这个Activity里面,我们需要做什么呢?
两件事情:
初始化相机
将内容显示到SurfaceView
Android的Camera是独享的,如果多处调用,就会抛出异常,所以,我们需要将Camera的生命周期与Sur