在Android手机中,相机应该算是每部智能手机的标准配置了,google为了方便开发者开发,提供了一套供开发者使用的api,作为软件开发者基本上只要调用这些接口就可以进行Android相机方面的功能开发了(这里指的只是基本功能,比如预览、拍照等)!

在本篇博客中将想你展示如何使用google提供的接口(Camera1,后面还会说到,google在后期的版本中推出了Camera2接口,在下一篇博客中在介绍如何使用Camera2接口)开发自己的相机。在这里使用到的类不多,主要包含:Camera、SurfaceView、SurfaceHolder等!

google在相机预览、拍照包括人脸识别中都提供了一个接口,直接调用就可以实现相应的功能,是不是感觉很简单,下面我们就来实现一个Camera(具有预览拍照功能,拍照的图片储存在这里就不实现了)!
先看一下布局文件吧:

<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="match_parent"    android:layout_height="match_parent">        <android.support.v4.widget.DrawerLayout            android:layout_width="match_parent"            android:layout_height="match_parent">                <FrameLayout                    android:background="@android:color/transparent"                    android:layout_width="match_parent"                    android:layout_height="match_parent">                    <SurfaceView                        android:background="@android:color/transparent"                        android:id="@id/camera_preview"                        android:layout_width="match_parent"                        android:layout_height="match_parent" />                FrameLayout>            <LinearLayout                android:layout_width="150dp"                android:layout_height="300dp"                android:layout_gravity="start|center_vertical"                android:background="@color/colorPrimary" />        android.support.v4.widget.DrawerLayout>        <RelativeLayout            android:layout_width="match_parent"            android:layout_height="wrap_content"            android:layout_alignParentBottom="true"            android:background="@android:color/transparent">            <ImageView                android:onClick="onCapturePhoto"                android:layout_width="wrap_content"                android:layout_height="wrap_content"                android:layout_centerInParent="true"                android:background="@android:color/transparent"                android:src="@drawable/photo_button" />        RelativeLayout>RelativeLayout>

写的有点啰嗦,其实要做demo的话,只需要一个SurfaceView即可,其他的即可抛弃!!!

再来看一下java代码的实现:

package com.example.administrator.beercamera;import android.app.Activity;import android.graphics.ImageFormat;import android.graphics.Paint;import android.hardware.camera2.CameraAccessException;import android.hardware.camera2.CameraCaptureSession;import android.hardware.camera2.CameraDevice;import android.hardware.camera2.CameraManager;import android.hardware.camera2.CaptureRequest;import android.hardware.camera2.CaptureResult;import android.hardware.camera2.TotalCaptureResult;import android.media.Image;import android.media.ImageReader;import android.os.Bundle;import android.support.annotation.NonNull;import android.util.Log;import android.view.SurfaceHolder;import android.view.SurfaceView;import android.view.View;import android.view.Window;import android.view.WindowManager;import java.util.Arrays;public class Camera2Activity extends Activity {    private SurfaceView mSurfaceView;    private SurfaceHolder mSurfaceHolder;    private CameraManager mCameraManager;    private CameraDevice mCameraDeivce;    private CameraCaptureSession mCameraSession;    private CaptureRequest.Builder mRequestBuilder;    private ImageReader mImageReader;    private SavePhotoListener mSaveListener;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        getWindow().requestFeature(Window.FEATURE_NO_TITLE);        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);        setContentView(R.layout.activity_main);        mCameraManager = (CameraManager) getSystemService(CAMERA_SERVICE);        mSurfaceView = (SurfaceView) findViewById(R.id.camera_preview);        mSurfaceHolder = mSurfaceView.getHolder();        mSurfaceHolder.addCallback(new SurfaceViewCallBack());        mSaveListener = new SavePhotoListener();    }    @Override    protected void onDestroy() {        super.onDestroy();        if(mCameraDeivce != null){            mCameraDeivce.close();        }    }    public void onCapturePhoto(View view) {        try {            final CaptureRequest.Builder mBuilder = mCameraDeivce.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);            mBuilder.addTarget(mImageReader.getSurface());            mBuilder.set(CaptureRequest.CONTROL_AE_MODE,CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH);            mBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);            mBuilder.set(CaptureRequest.CONTROL_AWB_MODE,CaptureRequest.CONTROL_AWB_MODE_AUTO);//            mImageReader.setOnImageAvailableListener(mSaveListener,null);            mCameraSession.stopRepeating();            mCameraSession.capture((mBuilder.build()),new CameraResultCallBack(),null);        } catch (CameraAccessException e) {            e.printStackTrace();        }    }    private boolean CheckPermission(){        return true;    }    private class SurfaceViewCallBack implements SurfaceHolder.Callback{        @Override        public void surfaceCreated(SurfaceHolder holder) {            try {                mCameraManager.openCamera("0",new CameraCallBack(),null);            } catch (CameraAccessException e) {                e.printStackTrace();            } catch (SecurityException e) {                e.printStackTrace();            }        }        @Override        public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {        }        @Override        public void surfaceDestroyed(SurfaceHolder holder) {        }    }    private class CameraCallBack extends CameraDevice.StateCallback{        @Override        public void onOpened(@NonNull CameraDevice camera) {            Log.e("zyq","onOpened");            mCameraDeivce = camera;            try {                mImageReader = ImageReader.newInstance(mSurfaceView.getWidth(),mSurfaceView.getHeight(), ImageFormat.JPEG,7);                mImageReader.setOnImageAvailableListener(mSaveListener,null);                mRequestBuilder = mCameraDeivce.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);                mRequestBuilder.addTarget(mSurfaceHolder.getSurface());                mCameraDeivce.createCaptureSession(Arrays.asList(mSurfaceHolder.getSurface(),mImageReader.getSurface()),new CameraCaptureConfig(),null);            } catch (CameraAccessException e) {                e.printStackTrace();            }        }        @Override        public void onDisconnected(@NonNull CameraDevice camera) {        }        @Override        public void onError(@NonNull CameraDevice camera, int error) {            if(camera != null){                camera.close();            }        }    }    private class CameraCaptureConfig extends CameraCaptureSession.StateCallback{        @Override        public void onConfigured(@NonNull CameraCaptureSession session) {            mCameraSession = session;            mRequestBuilder.set(CaptureRequest.CONTROL_AE_MODE,CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH);            mRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);            mRequestBuilder.set(CaptureRequest.CONTROL_AWB_MODE,CaptureRequest.CONTROL_AWB_MODE_AUTO);            try {                mCameraSession.setRepeatingRequest(mRequestBuilder.build(),null,null);            } catch (CameraAccessException e) {                e.printStackTrace();            }        }        @Override        public void onConfigureFailed(@NonNull CameraCaptureSession session) {        }    }    private class CameraResultCallBack extends CameraCaptureSession.CaptureCallback{        @Override        public void onCaptureProgressed(@NonNull CameraCaptureSession session, @NonNull CaptureRequest request, @NonNull CaptureResult partialResult) {            super.onCaptureProgressed(session, request, partialResult);            Log.e("zyq","onCaptureProgressed");        }        @Override        public void onCaptureCompleted(@NonNull CameraCaptureSession session, @NonNull CaptureRequest request, @NonNull TotalCaptureResult result) {            super.onCaptureCompleted(session, request, result);            mCameraSession = session;            Log.e("zyq","onCaptureCompleted");            try {                mCameraSession.setRepeatingRequest(mRequestBuilder.build(),null,null);            } catch (CameraAccessException e) {                Log.e("zyq","onCaptureCompleted e="+e.getMessage());                e.printStackTrace();            }        }    }    private class SavePhotoListener implements ImageReader.OnImageAvailableListener{        @Override        public void onImageAvailable(ImageReader reader) {            Log.e("zyq","save photo");            Image image = reader.acquireLatestImage();            if(image != null){                Log.e("zyq","iamge = "+image.getHeight()+" , "+image.getWidth());            }        }    }}

具体预览的效果图就不给出了,给一下拍照时的log吧,log如下;

06-03 14:29:47.689 21208-21208/com.example.administrator.beercamera E/zyq: save photo06-03 14:29:47.690 21208-21208/com.example.administrator.beercamera E/zyq: iamge = 1280 , 72006-03 14:29:47.700 21208-21208/com.example.administrator.beercamera E/zyq: onCaptureCompleted

在ImageReader回调函数中,即使你不打算存储图片也需要调用获取Image的方法,不然的话,下一次点击拍照会出现不执行回调函数的情况,有兴趣的朋友可以自己试一下,使用Camera2刚开始可能会不太习惯,但是认真看一下之后,你会觉的Camera2的架构更容易理解。

下面大致说一下,具体的我也没有追过Camera2的架构代码:
使用Camera2的api,你会发现一切的操作基本上都是通过请求完成,而对请求结果的处理都是通过回调接口完成:
比如我们需要拍摄照片,那么就需要构建一个新的请求,在请求中指定请求的类型为抓取照片,请求放回数据的输出目标为ImageReader中的Surface,然后在请求中添加一系列camera的参数等,然后通过会话传递这个请求基本上就可以达到获取照片的目的了,详细的还是看一下上面的代码!!!

现在来看一下Camera1的API接口的使用:

package com.example.administrator.beercamera;import android.app.Activity;import android.hardware.Camera;import android.os.Bundle;import android.support.annotation.Nullable;import android.util.Log;import android.view.SurfaceHolder;import android.view.SurfaceView;import android.view.View;import java.io.IOException;/** * Created by Administrator on 2017/5/28 0028. */@Deprecatedpublic class Camera1Activity extends Activity {    private SurfaceView mSurfaceView;    private SurfaceHolder mSurfaceHolder;    private Camera mCamera;    private SavePhotoListener mSavePhotoListener;    @Override    protected void onCreate(@Nullable Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        mSurfaceView = (SurfaceView) findViewById(R.id.camera_preview);        mSurfaceHolder = mSurfaceView.getHolder();        mSurfaceHolder.addCallback(new PreviewCallBack());        mSavePhotoListener = new SavePhotoListener();    }    public void onCapturePhoto(View view){        mCamera.takePicture(null,null,mSavePhotoListener);    }    private class PreviewCallBack implements SurfaceHolder.Callback{        @Override        public void surfaceCreated(SurfaceHolder holder) {            mCamera = Camera.open(0);            try {                mCamera.setPreviewDisplay(holder);            } catch (IOException e) {                e.printStackTrace();            }            mCamera.setDisplayOrientation(90);            mCamera.startPreview();        }        @Override        public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {        }        @Override        public void surfaceDestroyed(SurfaceHolder holder) {            mCamera.stopPreview();        }    }    @Override    protected void onDestroy() {        super.onDestroy();        if(mCamera != null){            mCamera.release();        }    }    private class SavePhotoListener implements Camera.PictureCallback{        @Override        public void onPictureTaken(byte[] data, Camera camera) {            Log.i("zyq","data length = "+data.length);            mCamera.startPreview();        }    }}

使用Camera1的时候,所有的操作都是一步接着一步的,首先打开相机,设置相关参数,开始预览、拍照等,这种思路很像我们平常操作手机中相机的步骤,感觉更符合我做事时思考的方式,但是Camera2肯定也有着它的优势,不然google没什么事干嘛推出Camera2呢!!

两者的区别主要是架构的不同,对于开发者来说,除了需要知道架构的不同外,我们还需要了解一下Camera2相关API的使用,不然还是不能很好的利用Camera2的接口进行相机编程的!!

好了关于Android相机这一块就说到这吧,其实要编写一个很好的Camera很是很难的,你需要考虑相机的各个方面的东西,兼容、设置、图片/视频的存储等,有条件的话可以看一下系统相机的源码,或者是MTK的相机,阅读源码还是很有收获的!!!有兴趣的朋友可以以关注我,遇到问题大家一起讨论一下!!

这是我的微信公众号,如果可以的话,希望您可以帮忙关注一下,这将是对我最大的鼓励了,谢谢!!

更多相关文章

  1. Android(安卓)面向接口编程
  2. App ReLoad:用Android(安卓)来控制单反相机
  3. Android实现自定义listview上拉刷新下拉加载以及侧滑编辑、删除
  4. Android中三种超实用的滑屏方式汇总
  5. 万能前端框架uni app初探01:搭建开发环境
  6. Android照相和录音功能的使用
  7. Android远程service aidl的用法
  8. 腾讯微博java(android) sdk 话题相关api详细介绍
  9. iPhone与Android谁更能倾倒开发者?

随机推荐

  1. Android 学习记录-ImageView显示格式
  2. Android虚拟机大屏幕设置
  3. android - JNI NewStringUTF字串的釋放
  4. 全网最全的Android资源汇总
  5. Android中后台显示悬浮窗口的方法
  6. Android(安卓)Fragment 你应该知道的一切
  7. 系出名门Android(4) - 活动(Activity),
  8. 更新Android SDK Tools, revision 7报错
  9. 从零开始学习android
  10. Android(安卓)Studio 生成Jar包