Android学习十---Android Camera
Android camera用来拍照和拍摄视频的先看一下最后实现的效果图
最后的效果图


一、准备
在你的应用程序上使用android拍照设备,需要考虑以下几个方面
1. 是否是一定需要camera
如果需要,那么就无法安装在没有摄像头的设备。
需要在mainfest 中声明
<uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.hardware.camera" />
2. 是想用怎样的方式来使用相机
可以有两种方式
2.1 简单的拍照 使用已经存在camera apps
2.2 需要更多定制的功能,创建一个camera app
3. 存储方式
是只能在本应用程序里使用还是可以被其他程序使用。
二、相关类
android.hardware.camera2
包中包含控制设备相机的基本类
Camera
过时不用的相机控制类
SurfaceView
提供实时的相机预览
MediaRecorder
用来记录video
Intent
使用
MediaStore.ACTION_IMAGE_CAPTURE
MediaStore.ACTION_VIDEO_CAPTURE
两个Intent类型来捕获图像和视频
三、Manifest声明
camera许可
<uses-permission android:name="android.permission.CAMERA" />
camera特征
<uses-feature android:name="android.hardware.camera" />
存储许可
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
音视频录制
<uses-permission android:name="android.permission.RECORD_AUDIO" />
位置许可
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
四、使用已经存在的camera apps
使用方式是用Intent,使用Intent能够使用最少的代码来获取图片
流程主要是
创建一个camera Intent,Intent的类型包括,MediaStore.ACTION_IMAGE_CAPTURE,启动一个camera Intent,使用startActivityForResult()方法来执行一个camera intent,在启动Intent后,camera应用界面能够显示在设备屏幕来供使用MediaStore.ACTION_VIDEO_CAPTURE
接受Intent的结果,使用onActivityResult()方法来接受Intent的回调和数据。当用户结束拍照后,系统调用这一方法。
下列代码显示如何创建一个camera intent并执行
private static final int CAPTURE_IMAGE_ACTIVITY_REQUEST_CODE = 100;
private Uri fileUri; @Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main); // create Intent to take a picture and return control to the calling application
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); fileUri = getOutputMediaFileUri(MEDIA_TYPE_IMAGE); // create a file to save the image
intent.putExtra(MediaStore.EXTRA_OUTPUT, fileUri); // set the image file name // start the image capture Intent
startActivityForResult(intent, CAPTURE_IMAGE_ACTIVITY_REQUEST_CODE);
}
接收camera intent的结果,主要是重载onActivityResult。
private static final int CAPTURE_IMAGE_ACTIVITY_REQUEST_CODE = 100;
private static final int CAPTURE_VIDEO_ACTIVITY_REQUEST_CODE = 200; @Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == CAPTURE_IMAGE_ACTIVITY_REQUEST_CODE) {
if (resultCode == RESULT_OK) {
// Image captured and saved to fileUri specified in the Intent
Toast.makeText(this, "Image saved to:\n" +
data.getData(), Toast.LENGTH_LONG).show();
} else if (resultCode == RESULT_CANCELED) {
// User cancelled the image capture
} else {
// Image capture failed, advise user
}
}
}
!一但程序接受到一个成功的结果,那么应用程序就可以获取在指定路径下的图片。
五、创建一个Camera App
官方建议使用新的android.hardware.camera2,使用旧的Camera API会出现deprecated的警告。
一般创建一个定制Camera接口的步骤包括
1.检测和获取camera
/** Check if this device has a camera */
private boolean checkCameraHardware(Context context) {
if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA)){
// this device has a camera
return true;
} else {
// no camera on this device
return false;
}
}
/** A safe way to get an instance of the Camera object. */
public static Camera getCameraInstance(){
Camera c = null;
try {
c = Camera.open(); // attempt to get a Camera instance
}
catch (Exception e){
// Camera is not available (in use or does not exist)
}
return c; // returns null if camera is unavailable
}
2.创建一个预览类
/** A basic Camera preview class */
public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {
private SurfaceHolder mHolder;
private Camera mCamera; public CameraPreview(Context context, Camera camera) {
super(context);
mCamera = camera; // Install a SurfaceHolder.Callback so we get notified when the
// underlying surface is created and destroyed.
mHolder = getHolder();
mHolder.addCallback(this);
// deprecated setting, but required on Android versions prior to 3.0
mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
} public void surfaceCreated(SurfaceHolder holder) {
// The Surface has been created, now tell the camera where to draw the preview.
try {
mCamera.setPreviewDisplay(holder);
mCamera.startPreview();
} catch (IOException e) {
Log.d(TAG, "Error setting camera preview: " + e.getMessage());
}
} public void surfaceDestroyed(SurfaceHolder holder) {
// empty. Take care of releasing the Camera preview in your activity.
} public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
// If your preview can change or rotate, take care of those events here.
// Make sure to stop the preview before resizing or reformatting it. if (mHolder.getSurface() == null){
// preview surface does not exist
return;
} // stop preview before making changes
try {
mCamera.stopPreview();
} catch (Exception e){
// ignore: tried to stop a non-existent preview
} // set preview size and make any resize, rotate or
// reformatting changes here // start preview with new settings
try {
mCamera.setPreviewDisplay(mHolder);
mCamera.startPreview(); } catch (Exception e){
Log.d(TAG, "Error starting camera preview: " + e.getMessage());
}
}
}
3.创建一个预览的布局
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<FrameLayout
android:id="@+id/camera_preview"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_weight="1"
/> <Button
android:id="@+id/button_capture"
android:text="Capture"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
/>
</LinearLayout>
public class CameraActivity extends Activity {
private Camera mCamera;
private CameraPreview mPreview;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// Create an instance of Camera
mCamera = getCameraInstance();
// Create our Preview view and set it as the content of our activity.
mPreview = new CameraPreview(this, mCamera);
FrameLayout preview = (FrameLayout) findViewById(R.id.camera_preview);
preview.addView(mPreview);
}
}
4.开始监听捕获事件
private PictureCallback mPicture = new PictureCallback() {
@Override
public void onPictureTaken(byte[] data, Camera camera) {
File pictureFile = getOutputMediaFile(MEDIA_TYPE_IMAGE);
if (pictureFile == null){
Log.d(TAG, "Error creating media file, check storage permissions: " +
e.getMessage());
return;
}
try {
FileOutputStream fos = new FileOutputStream(pictureFile);
fos.write(data);
fos.close();
} catch (FileNotFoundException e) {
Log.d(TAG, "File not found: " + e.getMessage());
} catch (IOException e) {
Log.d(TAG, "Error accessing file: " + e.getMessage());
}
}
};
5.捕获并保存文件
// Add a listener to the Capture button
Button captureButton = (Button) findViewById(id.button_capture);
captureButton.setOnClickListener(
new View.OnClickListener() {
@Override
public void onClick(View v) {
// get an image from the camera
mCamera.takePicture(null, null, mPicture);
}
}
);
保存图片到SD卡中
private PictureCallback mPicture = new PictureCallback() {
/** Create a File for saving an image or video */
@Override
public void onPictureTaken(byte[] data, Camera camera) {
File pictureFile = getOutputMediaFile();
if (pictureFile == null) {
Log.d(TAG,"Error creating media file, check storage permissions: ");
return;
}
try {
FileOutputStream fos = new FileOutputStream(pictureFile);
fos.write(data);
fos.close();
} catch (FileNotFoundException e) {
Log.d(TAG, "File not found: " + e.getMessage());
} catch (IOException e) {
Log.d(TAG, "Error accessing file: " + e.getMessage());
}
camera.startPreview();
}
};
private File getOutputMediaFile() {
// To be safe, you should check that the SDCard is mounted
// using Environment.getExternalStorageState() before doing this.
File mediaStorageDir = new File(
Environment
.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES),
"MyCameraApp");
// This location works best if you want the created images to be shared
// between applications and persist after your app has been uninstalled.
// Create the storage directory if it does not exist
if (!mediaStorageDir.exists()) {
if (!mediaStorageDir.mkdirs()) {
Log.d("MyCameraApp", "failed to create directory");
return null;
}
}
// Create a media file name
File mediaFile;
String timeStamp = String.format("%d.jpg", System.currentTimeMillis());
mediaFile = new File(mediaStorageDir.getPath() + File.separator
+ "IMG_" + timeStamp + ".jpg");
return mediaFile;
}
6.释放相机
public class CameraActivity extends Activity {
private Camera mCamera;
private SurfaceView mPreview;
private MediaRecorder mMediaRecorder;
...
@Override
protected void onPause() {
super.onPause();
releaseMediaRecorder(); // if you are using MediaRecorder, release it first
releaseCamera(); // release the camera immediately on pause event
}
private void releaseCamera(){
if (mCamera != null){
mCamera.release(); // release the camera for other applications
mCamera = null;
}
}
}
caution:
相机是一个共享资源,所以每次使用完毕后要记得调用Camera.release()来释放,否则后续想要获取相机的应用都会被关闭。
六、注意问题
6.1 拍完成照片后,停在拍照完成的界面,无法继续拍摄
在onPictureTaken的实现最后添加一个启动预览camera.startPreview();
private PictureCallback mPicture = new PictureCallback() {
/** Create a File for saving an image or video */
@Override
public void onPictureTaken(byte[] data, Camera camera) {
File pictureFile = getOutputMediaFile();
if (pictureFile == null) {
Log.d(TAG,"Error creating media file, check storage permissions: ");
return;
}
try {
FileOutputStream fos = new FileOutputStream(pictureFile);
fos.write(data);
fos.close();
} catch (FileNotFoundException e) {
Log.d(TAG, "File not found: " + e.getMessage());
} catch (IOException e) {
Log.d(TAG, "Error accessing file: " + e.getMessage());
}
camera.startPreview();
}
};
代码:
https://github.com/dawnminghuang/android_camera
参考资料
http://developer.android.com/guide/topics/media/camera.html
Android学习十---Android Camera的更多相关文章
- [置顶] Android学习系列-Android中解析xml(7)
Android学习系列-Android中解析xml(7) 一,概述 1,一个是DOM,它是生成一个树,有了树以后你搜索.查找都可以做. 2,另一种是基于流的,就是解析器从头到尾解析一遍xml文件. ...
- android 学习十四 探索安全性和权限
1.部署安全性:应用程序必须使用数字证书才能安装到设备上. 2.执行期间的安全性: 2.1 使用独立进程 2.2 使用固定唯一用户ID 2.3 申明性权限模型 3数字证书 ...
- Android学习十二---在android上实现图像匹配
一.效果图及功能描述 效果图 点击ShowImg后 点击match,然后点击showmatch,可以不断点击showmatch. 主要功能描述:显示在SD卡上已经存在的图片test.jpg,根据图片在 ...
- android学习十四(android的接收短信)
收发短信是每一个手机主要的操作,android手机当然也能够接收短信了. android系统提供了一系列的API,使得我们能够在自己的应用程序里接收和发送短信. 事实上接收短信主要是利用我们前面学过的 ...
- Android学习十二:自定义控件学习
自定义控件: 1.定义控件的属性,atts.xml 2.代码实现自定义控件的控制 3.引用该控件 首先定义相关的属性 <?xml version="1.0" encoding ...
- android学习十二(android的Content Provider(内容提供器)的使用)
文件存储和SharePreference存储以及数据存储一般为了安全,最好用于当前应用程序中訪问和存储数据.内容提供器(Content Provider)主要用于在不同的应用程序之间实现数据共享的功能 ...
- android学习十 ActionBar
1.api level大于等于11 支持,或者使用兼容库,但兼容库的问题很多. 2.一个操作栏属于一个活动,并具有其生命周期 3.操作栏分3类:a.选项卡操作栏,b.列表操作栏,c.标准操作栏 4.获 ...
- Android学习——在Android中使用OpenCV的第一个程序
刚開始学习Android,因为之前比較熟悉OpenCV,于是就想先在Android上执行OpenCV试试 =============================================== ...
- 【Android学习】android:layout_weight的用法实例
对于android:layout_weight的用法,用下面的例子来说明: <LinearLayout xmlns:android="http://schemas.android.co ...
随机推荐
- js----Open()函数
JS中open()函数介绍 window=object.open([URL ][, name ][, features ][, replace]]]]) URL:新窗口的URL地址 name:新窗口的 ...
- mysql获取插入的id主键
long _retId = -1; Connection con = null; try { con = queryRunner.getDataSource().getConnection(); qu ...
- javascript深入理解js闭包【手动加精】
http://www.jb51.net/article/24101.htm 闭包(closure)是Javascript语言的一个难点,也是它的特色,很多高级应用都要依靠闭包实现. 一.变量的作用 ...
- iOS-回收键盘的几种方法
在开发过程中,为了实现点击屏幕其它位置收起键盘的目的,我们使用过许多的方法. 如果是在UIViewController中收起键盘,除了通过调用控件的resignFirstResponder方法外,还有 ...
- Activiti(一)--安装配置具体解释
有一段时间没有更新文章了,尽管有一直在写文章,但是一直没有更新到博客内,这段时间写的文章大多还是以技术为主. 接下来的系列文章将会来讨论企业工作流的开发,主要是来研究开源工作流Activiti的使用. ...
- 如何使用NFS
这两个网卡之间可以通信的,如图所示 也可以写成具体的ip地址,或者ip地址段例如192.168.1.2-200 注意看下面这幅图,路径一定要写完整 下面开始挂载共享的目录 挂载之后什么都没有出现说明挂 ...
- Service Mesh服务网格新生代--Istio(转)
万字解读:Service Mesh服务网格新生代--Istio 官网地址:https://preliminary.istio.io/zh/docs/concepts/security/ Servic ...
- php ocket通信机制
php 实例说明 socket通信机制 一,socket是什么 什么是socket 所谓socket通常也称作"套接字",用于描述IP地址和端口,是一个通信链的句柄.应用程序通常通 ...
- 第二百零八节,jQuery EasyUI,SplitButton(分割按钮菜单)组件
jQuery EasyUI,SplitButton(分割按钮)组件 学习要点: 1.加载方式 2.属性列表 3.方法列表 本节课重点了解 EasyUI 中 SplitButton(分割按钮)组件的使用 ...
- 在java语言中int 和 Integer 有什么区别
在java语言中int 和 Integer 有什么区别 解答:int是基本数据类型,Integer是int的包装类,属于引用类型