第一步:拍照预览
第二步:相机参数设置、对焦实现、拍照存储在本地、拍照声音、闪光灯 自定义相机(二)
自定义相机(一)主要介绍,第一步拍照浏览功能的实现
主要涉及:
Camera类(注意是android.handware类下的,不是android.graphics类)(Camera2暂时不讨论)
SurfaceView类 SurfaceHolder类 SurfaceHolder.Callback回调接口
1.首先必需获取拍照需要的权限:
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"></uses-permission>
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.hardware.camera.autofocus" />
<uses-feature android:name="android.hardware.camera" />
2.接下来android的UI界面离不开Activity,所以我们创建个CameraActivity.java来显示相机
当然Camera类是必不可少的,它主要用来管理相机相关配置(闪光灯)和实现拍照功能
那SurfaceView又是干什么的呢?我们发现SurfaceView继承自View说明是视图,那就是用来显示
相机预览的。
SurfaceView做为相机专用View,为摄像等方法重写了很多方法,而且SurfaceView类会重新创建一个新的
单独线程绘制画面,而普通的View是在UI线程上绘制画面,我们知道UI线程阻塞超过5秒程序就会无响应,所以尽量
在子线程中执行消耗大的动作,带来良好的用户体验。
3.在写Activity之前先看看Google是如何继承重写SurfaceView的
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. 安装SurfaceHolder.Callback回调接口,
//以便SurfaceView 被创建和销毁时能及时得到通知(接口回调的本质是,给其他类能执行当前类重新实现的接口方法)
mHolder = getHolder();
mHolder.addCallback(this);
// deprecated setting, but required on Android versions prior to 3.0
//已弃用的设置,但在3.0之前的Android版本上需要
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.
// Surface已创建,现在告诉相机在哪里绘制预览
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());
}
}
}
4.SurfaceView已经完成,那怎么在Activity中使用呢?
public class CameraActivity extends Activity implements View.OnClickListener{
Camera camera=null;
private LinearLayout container;
private ImageView iv_camera;
private ImageView btn_camera;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//实现全屏,没有标题栏,也没有状态栏
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
setContentView(R.layout.activity_camera);
if (checkCameraHardware()){
openCamera();
initView();
}else {
Toast.makeText(this,"当前不支持相机!",Toast.LENGTH_SHORT).show();
}
}
private void initView(){
iv_camera=(ImageView) findViewById(R.id.iv_camera);
btn_camera=(ImageView) findViewById(R.id.btn_camera);
iv_camera.setOnClickListener(this);
iv_camera.setOnClickListener(this);
}
//开始预览相机
private void openCamera(){
if (camera==null){
//获得相机实例
camera=camera.open();
//注册容器控件
container=(LinearLayout)findViewById(R.id.ll_contain);
//实例化SurfaceView
CameraPreview cameraPreview=new CameraPreview(CameraActivity.this,camera);
container.addView(cameraPreview);
}
}
//释放相机资源
private void releaseCamera(){
if (camera!=null){
camera.setPreviewCallback(null);
camera.stopPreview();
camera.release();
camera=null;
}
}
// 判断相机是否支持
private boolean checkCameraHardware() {
if (this.getPackageManager().hasSystemFeature(
PackageManager.FEATURE_CAMERA)) {
return true;
} else {
return false;
}
}
//相机不使用时 释放资源
@Override
protected void onPause() {
super.onPause();
releaseCamera();
}
@Override
protected void onResume() {
super.onResume();
openCamera();
}
@Override
public void onClick(View v) {
}
}
值得注意的是,android的相机只能被一个APP线程绑定,所以同一时间内,不能打开两个相机,我们用完相机时应该释放camera(Camera.release()来释放相机资源)
5.Activity的布局文件
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:id="@+id/ll_contain"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent">
</LinearLayout>
<ImageView
android:id="@+id/iv_camera"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:background="@drawable/ic_focusing_begin"/>
<ImageView
android:id="@+id/btn_camera"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_centerHorizontal="true"
android:layout_alignParentBottom="true"
android:layout_marginBottom="10dp"
android:src="@drawable/ic_bt"/>
</RelativeLayout>
</LinearLayout>
运行程序发现(暂时没有拍照功能)有了拍照预览功能了,但是显示效果不佳,拍照方向不正确,尺寸不正确等
为什么会这样呢?自定义相机(二)我们将继续讲述...