Android Camera Develop: capture photo and video

概述

上篇完成了相机的偏好设置,本篇就要实现相机的核心功能——拍照和录像了。直觉上拍照和录像应该差别不大,但在Android中两者是有很大差别的,录像需要更多的步骤,以及更严格的处理逻辑。本篇还加入了对拍摄到的照片和视频的预览查看功能,就像其他相机APP那样。

生成文件名

因为拍照录像都是对相机的操作,所以这部分绝大多数都是在CameraPreview中添加代码。首先我们添加生成文件名这一功能,我们采用通用的做法,生成的文件名首先标记是照片还是视频,然后是拍摄的时间,比如IMG_20160503_153218.jpg和VID_20160505_080204.mp4。

在CameraPreview中添加

其中静态成员变量MEDIA_TYPE_IMAGE和MEDIA_TYPE_VIDEO标记文件为照片还是视频;outputMediaFileUri和outputMediaFileType则用来记录生成文件的URI和MIME类型。getOutputMediaFile()则根据参数中指定的文件类型,生成File类型的实例,供调用者写入文件;getOutputMediaFile()会在Android外部存储的图片路径下生成TAG文件夹,并在此生成文件,比如外部存储的Pictures/CameraDemo/;因为Android拍摄到的照片一般是jpg格式,视频一般是mp4格式,所以直接写死;最后生成的文件还会与outputMediaFileUri和outputMediaFileType同步,而getOutputMediaFileUri()和getOutputMediaFileType()则是对外的接口,后面再解释。

拍照

拍照主要用到的是Camera的takePicture()方法,通过指定回调函数,将照片数据写入到文件中。

在CameraPreview中添加

调用takePicture()时实际会调用mCamera.takePicture(),其第三个参数即指定回调函数;当相机拍照完成后,就会触发onPictureTaken(),其中data参数就是jpeg格式的照片数据。我们只需要调用getOutputMediaFile()获取输出文件,并向此文件写入照片数据就好了。

onPictureTaken()触发后相机会停止预览,此时我们手动添加camera.startPreview()让相机持续预览。另外takePicture()是一个异步过程,需要注意。

录像

录像部分的代码很多,但其中绝大部分都是来自Android官方文档的,基本就是一个不变的套路。录像是交给MediaRecorder类在做,大体上来说就是实例化一个MediaRecorder,向其指定一系列参数,然后start()开始录像,stop()结束录像。

在CameraPreview中添加

prepareVideoRecorder()即实例化MediaRecorder为成员变量mMediaRecorder,指定相机、音频源、视频源、录制视频参数、输出文件路径以及预览等,关于细节请查看官方文档。

其中的

是从Preference中读取视频分辨率偏好设置,并将其应用到mMediaRecorder;实际上这一步可以省略,录制的视频分辨率会和相机预览分辨率保持相同。

startRecording()首先调用prepareVideoRecorder()准备录像(如果不成功则放弃),start()开始录像。stopRecording()则调用stop()结束录像,并通过releaseMediaRecorder()完成收尾工作。isRecording()则用来判断当前是否正在录像。

申请权限

录像需要用到音频,而生成文件需要写入外部存储

在AndroidManifest.xml中添加

添加按钮

上述只是完成了方法的设计,现在就要在UI上添加按钮,并实际调用啦。

添加按钮

修改activity_main.xml为

UI大概像这样

绑定事件

在MainActivity的onCreate()最后添加

并在

前加final修饰符,即

绑定拍照很容易不解释。录像会有开始和结束两种状态,这里我们仅用一个按钮实现,处理逻辑也很简单,主要就是用isRecording()判断当前状态,根据当前状态选择处理方法,并修改button的text属性。

运行一下试试

这样就完成了拍照和录像的基本功能,你可以在真机上运行APP,点击“拍照”和“录像”了,生成的文件你可以在外部存储Pictures文件夹下的文件夹中找到。

解决后台返回时黑屏的问题

上一篇文章说到过这一篇会解决这个问题,现在就来着手解决啦,也是为下一节作铺垫。

原因分析

这里就不长篇大论从Activity的生命周期和View的关系细节讲了。黑屏的原因很简单,MainActivity在被切换到后台时,其本身的状态是保留的,但在其中的CameraPreview却被销毁了;当MainActivity从后台返回后,MainActivity状态恢复,而CameraPreview只在其onCreate()中实例化和加入窗口中,但MainActivity不会再触发onCreate(),造成黑屏。

解决方法

分析出上述原因后,解决方法也容易得出了。MainActivity在从后台返回时,会触发onResume(),我们只需要在其中像在onCreate()中一样完成整个CameraPreview的初始化,就解决这个问题了。

分离CameraPreview初始化语句

为了之后的方便,将onCreate()中涉及到CameraPreview初始化的语句独立为方法,将onCreate()中的

替换为

在MainActivity中添加

注意由于mPreview的处理分离,将mPreview提升为成员变量;原先添加的final CameraPreview删去,变更为对成员变量的赋值。

重载onResume

为了安全起见,也对onPause()重载,在MainActivity中加入

当APP切换到后台时触发onPause(),此时mPreview被销毁,将其赋值null;当从后台切换回来时,重新对mPreview初始化。

运行一下试试

现在把APP切换到后台再切换回来就不会出现黑屏的问题了。

添加预览

这里的预览不是相机预览了,是拍到的照片和视频的预览。目前常见的相机APP在拍照后,左下角或某个角落的小框就会马上显示新拍到的照片,点击这个小框就会全屏显示这个照片,现在我们就来实现这个功能。

预览框实际是ImageView,通过向ImageView指定图片或图片的URI,就可以在UI上显示这个图片了。那么对于拍到的视频怎么显示呢?这里我们可以获取到视频的预览图,将这个预览图指定给ImageView就好了。

添加预览框

修改activity_main.xml,在RelativeLayout内的LinearLayout之下加入

就会在窗口的右下角出现一个黑框,效果如下:

加入预览

之前提到拍照时异步操作,因为这个原因,我们将ImageView的操作交给CameraPreview处理。

修改CameraPreview

我们需要修改takePicture()和stopRecording()这两个方法,将其参数加上ImageView,并在其内部进行处理。

修改后的takePicture()如下

相比于之前,加入了参数final ImageView view,以及在文件写入完成后加入了

即指定ImageView的URI为刚才生成的照片文件。

修改后的stopRecording()如下:

相比于之前,加入了参数final ImageView view,以及在录像完成后加入了

第一句是根据指定的视频路径,生成了一张视频预览图;第二句则将这个图片交给ImageView显示。

修改MainActivity

我们还需要在MainActivity中找到ImageView,并在调用上述两个方法时添加参数。

在onCreate()中加入

修改

修改

运行一下试试

现在每拍到新照片或视频,预览框都会同步更新了。如下

点击预览框全屏显示

只是在预览框中显示拍到的照片或视频预览还是不够的,我们还想要点击这个预览框时能够全屏显示照片,或播放视频,下面我们就来实现这一功能。

先说思路,监听ImageView的点击事件,当点击时,通过Intent创建并显示一个新的Activity,同时MainActivity将需要显示的照片或视频的URI和MIME交给新的Activity,而这个新的Activity则负责显示照片和播放视频。在需要时,用户点击后退,回到MainActivity。

修改MainActivity

在onCreate()的最后加入

即对ImageView的点击事件监听,点击时创建一个新的Intent,新的Activity是ShowPhotoVideo(稍后创建);然后通过Data和Type向这个Intent传递拍到的照片或视频的URI和MIME(也可以用setExtra()实现,但这个方法更直观准确);最后启动这个Activity,并加入回退栈,使得点击后退时能够返回到MainActivity(上一步解决的后台返回黑屏问题也在这个得到应用)。

创建ShowPhotoVideo

这个类继承自Activity,功能很简单,根据Type判断使用ImageView显示照片,或使用VideoView显示视频,然后向ImageView或VideoView传递Data包含的URI信息。

创建ShowPhotoVideo类

文件内容如下:

与其他Activity不同的是,ShowPhotoVideo没有layout文件,其布局等在onCreate()中用代码生成。首先新建一个RelativeLayout即relativeLayout;再创建一个layout参数layoutParams,其参数设置长和宽均为MATCH_PARENT,随后像参数加入新规则CENTER_IN_PARENT,即居中显示。新建了ImageView或VideoView后,将view指定layoutParams参数,并将view加入到relativeLayout中。最后将本Activity的布局指定为刚才创建的relativeLayout,并设置layout参数为layoutParams。

对于ImageView和VideoView的选择和操作。根据Type决定实例化ImageView或VideoView,若实例化ImageView,则指定其URI为Data参数,指定layout参数后加入到layout中;若实例化VideoView,则同时还会实例化MediaController用来对播放视频进行控制,在对MediaController进行初始化操作后,将VideoView指定layout参数后加入到layout中。

再说下工作过程。MainActivity创建ShowPhotoVideo的Intent,并传递照片或视频的URI和MIME,然后切换到新的Activity即ShowPhotoVideo;ShowPhotoVideo创建时触发onCreate(),通过MIME实例化ImageView或VideoView,用代码生成布局并将ImageView或VideoView加入到布局,最后将布局应用到ShowPhotoVideo,完成整个工作过程。

修改AndroidManifest

Intent操作时需要在AndroidManifest.xml中提前声明Activity,这里我们就是要将ShowPhotoVideo加入到声明中。

在application中添加新的Activity,如下

运行一下试试

现在运行APP在拍照或录像后,点击预览框就能够全屏显示照片或播放视频了。比如点击视频预览图后

一点唠叨

直到本文,我们就实现了一个基本能用的相机APP了,为了代码的简洁和逻辑的清晰考虑,没有做太多特殊情况的处理,所以还会有各种各样的小bug,你可以自己进行优化。另外还会有一些功能上的增强和细节上的优化,会在随后的文章中介绍。

DEMO

参考

android 相机和照片一起_Android相机开发(三): 实现拍照录像和查看相关推荐

  1. VLC播放器Demo(录像,截图等功能),Android播放器Demo可二次开发。ffmpeg-Kit (录像,截图,合流播放,合流推送,等一些列视频操作功能),可二次开发。

    VLC播放器Demo(录像,截图等功能),可二次开发. ffmpeg-Kit (录像,截图,合流播放,合流推送,等一些列视频操作功能),可二次开发. 如果帮助的到了您,请您不要吝啬你的Star,先谢谢 ...

  2. android pin码 经典蓝牙_Android蓝牙开发—经典蓝牙详细开发流程

    Android蓝牙开发-经典蓝牙详细开发流程 发布时间:2018-07-16 13:41, 浏览次数:637 , 标签: Android Android蓝牙开发前,首先要区分是经典蓝牙开发还是BLE( ...

  3. 微信开发 调用摄像机拍照(录像)功能

    这样会调取摄像机  执行拍照功能 <input type="file"  capture="camera" accept="image/*&qu ...

  4. android触屏对焦_Android相机开发(五): 触摸对焦,触摸测光,二指手势缩放

    Android Camera Develop: touch to focus, touch to metering, double finger touch to zoom 概述 本篇在(四)的基础上 ...

  5. 【Android笔记67】Android之使用系统中的相机功能(拍照、保存照片、显示拍摄的照片、照片保存到图库等操作)

    这篇文章,主要介绍Android如何使用系统中的相机功能(拍照.保存照片.显示拍摄的照片.照片保存到图库等操作). 目录 一.使用Android相机功能 1.1.如何调用相机功能 1.2.调用相机功能

  6. Android开发学习之以CameraAPI方式实现相机功能(一)——快速实现相机

    今天无意当中发现在<Android开发学习之基于ZBar实现微信扫一扫>中的一部分代码可以用来以硬件方式实现一个照相机的功能,在<Android开发学习之调用系统相机完成拍照的实现& ...

  7. Android 11适配指南之系统相机拍照、打开相册,安卓app开发教程

    Android 6 权限适配 Android 7 文件适配 Android 10/11 存储适配 ok,接下来以一个更换头像的小例子来讲解一下. 示例 ======================== ...

  8. 安卓用户又少了一项自由,Android 11不再支持更改默认相机程序

    萧萧 发自 凹非寺 量子位 报道 | 公众号 QbitAI 在微博.微信上想要拍照上传时,想直接用FaceU或美图秀秀作为默认拍照程序,给自拍加个滤镜? 在即将推出的Android 11里,这些第三方 ...

  9. Android11还能自定义相机吗,安卓用户又少了一项自由,Android 11不再支持更改默认相机程序...

    原标题:安卓用户又少了一项自由,Android 11不再支持更改默认相机程序 来源:量子位 关注前沿科技 萧萧 发自 凹非寺 量子位 报道 | 公众号 QbitAI 萧萧 发自 凹非寺 量子位 报道 ...

最新文章

  1. shell中和||的使用方法
  2. Javascript获取select下拉框选中的的值以及索引
  3. 测试三相无刷电机驱动器 XXD2212 电调
  4. 【软件构造】第二章 软件构建的过程和工具(2)
  5. 关系数据库的查询建表
  6. Xilinx_ISE和ModelSim的联合使用方法 / 从Xilinx ISE 14.7启动ModelSim时遇到的问题
  7. 盘点程序员必备的专业术语,值得看一看
  8. php代码建议,php代码优化建议
  9. EVE-NG模拟器综合
  10. 想入行SAP咨询,最具性价比的方式
  11. php和plc哪个难,致PLC初学者的入门一课,七大误区如何解决?
  12. 【PCL自学:Feature7】基于转动惯量和偏心量的描述符 (持续更新)
  13. (转)简体繁体转换代码(Big5-GB | GBK简体-GBK繁体)
  14. Ubuntu16安装VScode、linux安装vscode、极简极稳安装vscode、umake安装vscode
  15. js 修改meta标签 属性
  16. 2021年茶艺师(中级)考试报名及茶艺师(中级)免费试题
  17. android生成将布局生成海报保存并分享
  18. 【C语言】scanf函数格式控制符
  19. GNU LGPL协议
  20. 从阿尔法元到人工智能会取代你的工作吗?

热门文章

  1. android 复制应用程序,Android限制复制,粘贴在应用程序之间查看
  2. arcgisserver修改服务器地址,ArcGIS 10.1 for Server入门(7-6)ArcGIS for Server 10.1 服务迁移与恢复--多台服务器...
  3. three.js场景中看不到模型/看不到阴影
  4. .net工具类 获取枚举类型的描述
  5. Python数据科学库-小测验
  6. 关于Chrome Devtools你可能有所不知的几个技巧
  7. java持久层框架mybatis如何防止sql注入
  8. 【数据结构amp;amp;等差数列】KMP简介和算法的实现(c++ amp;amp; java)
  9. Hyper-V动态扩展或差异磁盘体积缩小技巧
  10. UIScrollView的几个要点总结