首页 > 编程知识 正文

android网络编程详解,android应用开发详解

时间:2023-05-03 07:53:15 阅读:263715 作者:484

概述

Android提供了俩种使用相机的方式

一种是直接通过Intent调用系统相机组件,这种方法快速方便,适用于直接获取照片的场景另一种是使用相机Api来自定义相机,这种方法用于需要定制相机界面或开发相机特殊功能的场景 相机中的关键API

Camera开发主要用到了来个类

Camera类:最主要的类用于管理和操作camera资源,它提供了完整的相机底层接口SurfaceView 或TextureView:负责把Camera的数据显示在屏幕上 Camera类的API解释getNumberOfCameras获取设备的相机数量,一般有俩个 前置相机和后置相机open(CameraId)获取Camera实例,传入参数1 是获取前置摄像头, 0 为后置摄像头getParameters获取相机的参数,包括闪光灯模式,对焦模式,预览和拍照尺寸setParameters把自己设置好的相机参数,设置给相机setPreviewDisplay(SurfaceHolder)绑定预览图像的SurfaceView,当相机和surfaceView绑定后,相机预览的图像会通过surfaceView显示在屏幕上setPreviewTexture(SurfaceTexture)绑定预览图像的TextureView,当相机和TextureView绑定后,相机预览的图像会通过TextureView显示在屏幕上setPreviewCallback获取相机的预览数据setDisplayOrientation设置预览画面,顺时针旋转的角度startPreview开始预览stopPreview停止预览release释放相机takePicture(Camera.ShutterCallback shutter, Camera.PictureCallback raw, Camera.PictureCallback jpeg)这个是实现相机拍照的主要方法,包含了三个回调参数。shutter是快门按下时的回调,raw是获取拍照原始数据的回调,jpeg是获取经过压缩成jpg格式的图像数据的回调。getCameraInfo(int cameraId, CameraInfo cameraInfo)获取指定id的相机信息startFaceDetection开始人脸检测stopFaceDetection停止人脸检测setFaceDetectionListener设置人脸监听回调

我们继续看一下Camera类的内部类Parameters

上面我们说到一个getParameters方法,这个方法的返回值就是Parameters类

Camera.Parameters类的Api解释getSupportedPreviewSizes获取相机支持预览图片大小setPreviewSize(640, 480);设置预览图片带下,这里就是设置预览图片为640*480getSupportedPreviewFormats获得相机支持的图片预览格式,所有的相机都支持ImageFormat.NV21更多的图片格式可以自行百度或是查看ImageFormat类setPreviewFormat(int pixel_format)设置预览图片的格式getSupportedPictureSizes获取相机支持采集的图片大小(就是拍摄照片的带下)setPictureSize(int width, int height)设置拍摄照片的大小getSupportedPictureFormats获取相机支持的图片格式setPictureFormat设置拍摄图片的格式getSupportedFocusModes获取相机支持的对焦模式setFocusMode设置相机对焦模式getMaxNumDetectedFaces返回当前相机所支持的最大的人脸检测个数SurfaceView

用于绘制相机预览图像,提供给用户实时的预览图像,普通的View以及派生类都是共享一个Surface的,所有的绘制都需要在UI线程中,而SurfaceView是一种比较特殊的View,他不与其他普通View共享Surface,而是在他内部有一个独立的Surface,SurfaceView只负责管理这个Surface的格式尺寸以及显示位置,由于Ui线程还需要处理其他Ui交互,并不能保证View的更新速度和帧率,而SurfaceView有一个独立的Surface,因此可以在独立线程中绘制,因此可以提高更高的帧率

SurfaceView的优缺点

优点:

可以在一个独立的线程绘制,不会影响主线程使用双缓冲机制,播放视频更流畅
双缓冲机制:SurfaceView更新视图时用到了俩个Canvas,一个frontCanvas一个backCavans,每次实际显示的就是frontCanvas,backCavans储存的是上一次跟改前的视图,当lockCanvas()获取画布时,实际得到的是backCavans,而不是正在显示的frontCanvas,之后你在backCavans绘制视图,再unlockCanvasAndPost(canvas)这个视图,那么上传的canvas会替代frontCanvas,而原来的frontCanvas将切换到后台作为backCavans

缺点:

SurfaceView它的显示也不受View的属性控制,所以不能进行平移,缩放等变换,但是在7.0以后SurfaceView可以进行平移,缩放等

SurfaceHolder:SurfaceHolder是控制Surface的一个抽象接口,它能够控制Surface的尺寸格式,修改surface的像素,监听surface的变化等,Surface的典型用例就是用于SurfaceView中,通过getHolder获取SurfaceHolder,来监听Surface的状态

SurfaceHolder.Callback接口:负责监听Surface状态变化的接口,有三个方法

surfaceCreated(SurfaceHolder holder):当Surface被创建后立即被调用,在这里可以进行打开相机资源的操作surfaceChanged():当Surface的size发生变化时调用surfaceDestroyed(SurfaceHolder holder):当Surface被销毁时调用,可以在这里清相机资源 TextureView

TextureView继承自View,他将内容流直接投影到View中,和SurfaceView不同的是,他是一个普通的View,他可以平移,缩放等,他必须运行在硬件加速的窗口中

优点

他可以向普通的View一样进行平移缩放,截图

缺点

他必须运行在硬件加速的窗口,内存占用比SurfaceView高,5.0之前是在主线程渲染,5.0之后有单独的渲染线程


那么怎么选择这俩个控件

在7.0系统上SurfaceView比TextureView更有优势,可以使用动画,并且不会有黑边,如果在7.0以下有动画效果那么就需要用到TextureView

从安全和性能上考虑应该使用SurfaceView

自定义相机预览开发步骤 添加权限
在 Android Manifest.xml 中添加相机权限 <uses-permission android:name="android.permission.CAMERA" /> 把SurfaceView写入XML <SurfaceView android:id="@+id/surface" android:layout_width="match_parent" android:layout_height="match_parent" android:visibility="visible"/> 监听Surface状态 surfaceView = findViewById(R.id.surface); surfaceView.getHolder().addCallback(surfaceCallback); private SurfaceHolder.Callback surfaceCallback = new SurfaceHolder.Callback() { @Override public void surfaceCreated(SurfaceHolder holder) { //在这里打开相机 } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { } @Override public void surfaceDestroyed(SurfaceHolder holder) { //在这里回收相机资源 } }; 查看摄像头数量 int cameras = Camera.getNumberOfCameras();

这个方法返回相机的数量,在有前后摄像头的手机,会返回数量2

打开摄像头 mCamera = Camera.open(0);

传入参数CameraId,通常0为后置摄像头,1为前置摄像头

设置旋转角度和参数 mCamera.setDisplayOrientation(90); Camera.Parameters parameters = mCamera.getParameters(); parameters.setPreviewFormat(ImageFormat.NV21); //预览大小设置 parameters.setPreviewSize(640, 480); mCamera.setParameters(parameters);

设置预览画面,顺时针旋转角度,和设置预览画面的大小,可以设置的参数有很多参考上方的API

开始预览 mCamera.setPreviewDisplay(surfaceView.getHolder()); mCamera.startPreview(); 拿到预览数据 mCamera.setPreviewCallback(new Camera.PreviewCallback() { @Override public void onPreviewFrame(byte[] data, Camera camera) {//这里的data就是每一帧的数据 } });

完整的代码

private void initView() { surfaceView = findViewById(R.id.surface); surfaceView.getHolder().addCallback(surfaceCallback); } private SurfaceHolder.Callback surfaceCallback = new SurfaceHolder.Callback() { @Override public void surfaceCreated(SurfaceHolder holder) { start(); } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { } @Override public void surfaceDestroyed(SurfaceHolder holder) { } }; public void start() { if (mCamera == null) { mCamera = Camera.open(0); } //因为横屏 mCamera.setDisplayOrientation(90); try { Camera.Parameters parameters = mCamera.getParameters(); parameters.setPreviewFormat(ImageFormat.NV21); //预览大小设置 parameters.setPreviewSize(640, 480); mCamera.setParameters(parameters); mCamera.setPreviewDisplay(surfaceView.getHolder()); mCamera.setPreviewCallback(new Camera.PreviewCallback() { @Override public void onPreviewFrame(byte[] data, Camera camera) { } }); mCamera.startPreview(); } catch (Exception e) { e.printStackTrace(); } } //摄像头数据的回调 @Override public void onPreviewFrame(byte[] data, Camera camera) { } 开发相机所遇到的坑

相机的预览方向问题

我们先了解一下基本概念

相机的数据都来自于相机硬件的相机传感器,这个传感器被固定到手机后,会有一个默认的取景方向,且不会改变相机预览的时候有一个预览方向,可以通过setDisplayOrientation方法设置相机采集照片也是有一个方向的,与预览方向无关屏幕坐标:在Android 中屏幕左上角是坐标的原点(0,0),原点向右是X轴正方向,原点向下是Y轴正方向自然方向:每个设备都有一个自然方向,手机和平板的自然方向不同,手机的自然方向是portrait(竖屏),平板的自然方向是landscape(横屏)图像传感器的方向:手机相机的图像数据来自于手机硬件的图像传感器,这个传感器固定到手机上之后会有一个默认的取景方向

相机的预览方向:将图像传感器捕捉到的图像,显示在屏幕上的方向,默认情况下和屏幕的方向一致,在相机APIsetDisplayOrientation方法可以设置预览方向,默认为0,和传感器方向一致
相机采集图像方向:相机采集图像后需要顺时针旋转
通过setDisplayOrientation设置预览方向,使预览方向为自然方向,前置摄像头在进行旋转之前,图像会进行一个水平方向的翻转,所以用户在看预览图形时会像照镜子绝大部分手机的传感器方向是横向的,且不能改变,所以要旋转90或270,也就是说保存图片时需要对图片进行旋转摄像头获取的帧数据,并不会随着预览方向改变

SurfaceView预览图像变形,拍摄照片图像变形问题

首先我们先明白三个概念

SurfaceView尺寸:即自定义相机中显示图像的SurfaceView的大小,当他铺满全屏时,就是屏幕的大小,这里称为手机预览图像PreViewSize:相机硬件提供预览帧图像的大小,预览帧传给SurfaceView,实现图像的显示,这里称为相机预览图像Picturesize:相机硬件提供拍摄帧数据尺寸的大小,拍摄数据可以形成位图文件,最终保存为jpg等形式,这里称为相机拍摄图像手机预览图像由相机预览图像生成,拍摄的照片由相机拍摄图像生成

问题

手机中预览的问题被拉伸被拉伸
这个是由于SurfaceView尺寸和PreViewSize长宽比例不同导致,因为手机预览图像是由相机预览图像生成,所有长宽比例不一致,必定会被拉伸

拍摄照片物体被拉伸
这种是由PreViewSize和PictureSize,长宽比例不同导致,总之为了避免这些问题的发生,SurfaceView、PreviewSize、PictureSize这三者的长宽尺寸需要比例相同,可以通过camera.getSupportedPreviewSizes()和camera.getSupportedPictureSizes()获取支持的尺寸,然后筛选和SurfaceView尺寸比例相同的数据,设置给相机,注意,市场上主流的长宽比例尺寸为4:3和16:9,所以SurfaceView尺寸不能太奇葩

锁屏下资源的释放

如果Home键切换后台或者锁屏后,就应该关闭资源把相机释放掉,可以在onResume和onPause中释放相机

参考:https://juejin.im/entry/58b4ccd944d904006a1ce446
https://www.jianshu.com/p/f8d0d1467584
https://juejin.im/entry/5912ba2d128fe10058694030
https://zhuanlan.zhihu.com/p/20559606

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。