摘要:文章提供了可以工作的实例,介绍了在应用中使用安卓Camera SurfaceView拍照的实现细节。
这是使用Fragment在Android Studio开发相机应用系列文章5篇中的第4篇。如果你没有读过之前的文章,先从GitHub上复制一份我的工程,这篇教程主要讨论”NativeCameraFragment“。
作者语:由于设备厂商庞多繁杂,不同版本相机API不同,一个完整健壮的相机应用是很复杂的。如果你想实现一个完整可行的,可以考虑以CWAC Camera为基础进行开发。我的目标仅仅是演示相机开发的一些基础。
除了安卓的原生相机应用,你也可以在自己的项目中使用相机功能。这涉及到直接利用安卓相机接口并把结果投射到“预览”界面或者SurfaceView上。
开启相机
一旦Fragment视图对象被创建,首先做的就是把相机和相机预览界面关联起来。你可以在谷歌的开发者网站上阅读相关的文档,下面是一个参考实现:
1 2 3 4 5 6 7 8 9 10 |
private boolean safeCameraOpenInView(View view) { boolean qOpened = false; releaseCameraAndPreview(); mCamera = getCameraInstance(); qOpened = (mCamera != null); mPreview = new CameraPreview(getActivity().getBaseContext(), mCamera); FrameLayout preview = (FrameLayout) view.findViewById(R.id.camera_preview); preview.addView(mPreview); return qOpened; } |
该函数用来获取一个相机的实例对象并和我们的CameraPreview对象关联起来。
相机预览界面
例子中的CameraPreview 对象继承了SurfaceView 并实现了SurfaceHolder.callback接口,预览界面将显示相机的输入。在你看到正在拍摄的画面的同时,它将处理SurfaceHolder的生命周期:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 |
/** * Surface on which the camera projects it's capture results. */ class CameraPreview extends SurfaceView implements SurfaceHolder.Callback { SurfaceHolder mHolder; 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) { e.printStackTrace(); } } 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){ e.printStackTrace(); } } } |
相机拍照回调
Camera.PictureCallback是安卓用来判断何时相机拍摄了照片,并且获取了输出结果的回调接口。在我的示例项目工程中实现如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
private Camera.PictureCallback mPicture = new Camera.PictureCallback() { @Override public void onPictureTaken(byte[] data, Camera camera) { File pictureFile = getOutputMediaFile(); if (pictureFile == null){ Toast.makeText(getActivity(), "Image retrieval failed.", Toast.LENGTH_SHORT) .show(); return; } try { FileOutputStream fos = new FileOutputStream(pictureFile); fos.write(data); fos.close(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } }; |
免责声明和补充
文章一发布我就从安卓相机跨设备开发专家那得到了反馈,我的目标是提供高质量的内容,所以不说清楚下面的这些问题文章就不完整 。
在我的例子中假定设备支持jpeg格式,这种假定存在风险,真实的实现需要检查是否支持jpeg格式。另一个问题 CameraHolder.PreviewCallback接口直到API版本18许多厂商才支持,这使得API 18以前PreviewCallback 将难以起作用。
此例中,我使用的默认CameraPreview 格式是NV21,已经有人推荐我使用YV12(从API 12开始支持),一定要检查下相机支持的CameraPreview格式。实现格式因设备厂商不同而不同,是不一致行为的潜在根源。
还有包括闪光灯和聚焦模式在内的很多细节问题没有探讨,这些可能需要设置一些相机的参数,我已经在GitHub上更新了代码。
以上就是我直接使用安卓原生相机的例子,随便获取例子代码,同样,如果你觉得这篇文章对你有帮助欢迎分享。非常感谢。