对于基于摄像头的Android应用,实时取景是一个基本前提,通过前置或后置摄像头持续获取捕获到的内容,可以进一步做处理(人脸检测、美颜、滤镜等)。

所谓实时取景,简单说就是调用android的摄像头,把摄像头捕获的内容显示在apk的界面上。只要应用不关闭,相机就持续捕获,apk上看到的就是实时的取景了。

采用SurfaceView和Camera来做这件事。
是SDK自带的SurfaceView类而不是实现它的子类;在布局XML文件中使用SurfaceView而不是FrameLayout。因此,代码量很少也很容易理解。

从View到SurfaceView

android应用,和用户交互的GUI界面,是搭载在Activity上的。Activity创建的时候,往往会做setContentView(R.id.main_layout),这是根据xml布局文件设定要预先确定好的各种view对象,这些组件在xml中进行设计、设定。当然也可以在Java代码中进一步动态增加view对象。相当于layout作为各种view的容器。

android sdk自带了很多view的子类供使用。

View本身:继承自java.lang.Object类,实现了Drawable.Callback, KeyEvent.Callback, AccessibilitiyEventSource接口。
直接子类有:
AnalogClock:模拟时钟,有3个指针那种。
ImageView:显示图像。其实,任何Drawable对象都可以用ImageView来显示。
KeyboardView:内置键盘。
MediaRouteButton:媒体路由按钮(不太懂。似乎和多媒体、网络路由相关)
ProgressBar:(可视化)进度条展示。
Space:空白视图。轻量级视图。作用:在不同组件之间插入缝隙、间隔。
SurfaceView:提供了一个专门用于绘制的Surface。Surface的格式、尺寸可以控制。SurfaceView控制这个surface的绘制位置。。。中文翻译
TextView:文本视图。
TextureView:纹理视图。sdk4.0之后的API中可用。常被拿来和SurfaceView比较。
ViewGroup:用来容纳其他view对象。是layout(布局)和view containers(视图容器)的基类。
ViewStub:视图存根。大小为0、不可见,用来占坑的,apk运行时把坑交给资源。

间接子类有:
AbsListView
AbsSeekBar
AbsSpinner
AbsoluteLayout
AdapterView
AdapterViewAnimator
AdapterViewFlipper
以及其他56个间接子类。

可以看到,SurfaceView和TextureView两个view子类,都能用于实时取景框的显示。但是考虑到TextureView需要开启硬件加速的支持,不考虑。以及,目前看来SurfaceView本身也能胜任实时取景的任务。

代码

layout文件:surfaceview_main.xml

看到很多教程用的都是FrameLayout,而不是SurfaceView。我很不理解:为什么不用SurfaceView呢?不好用吗?
anyway,我这里就用SurfaceView了,在我测试过的代码中是完全可用的。

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/container"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical"
tools:context="com.example.chris.myapplication.MainActivity"><SurfaceViewandroid:id="@+id/surfaceView"android:layout_width="fill_parent"android:layout_height="wrap_content"android:layout_weight="1"/></LinearLayout>

java代码 ChrisActivity.java

Surface、SurfaceView、SurfaceHolder这三者相当于MVC的存在,Surface是数据,SurfaceView负责显示,SurfaceHolder控制了Surface。通过让Activity实现SurfaceHolder.Callback接口,开发者自行实现下面三个函数,开发者就完成内容的处理:

public void surfaceCreated(SurfaceHolder holder);
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height);
public void surfaceDestroyed(SurfaceHolder holder);

而具体到实现,一些额外的细节也要考虑到:相机的初始化和释放;应用暂停时释放相机,恢复时获取相机;屏幕方向与显示方向的一致。所以有如下代码:

package com.example.chris.myapplication;import android.app.Activity;
import android.hardware.Camera;
import android.os.Bundle;
import android.util.Log;
import android.view.Display;
import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.WindowManager;import java.io.IOException;/*** Created by chris on 2017/6/25.* 网上找了一些博客、教程和代码,稍微有点头绪了,现在写自己的Activity代码*/@SuppressWarnings("deprecation")
// TODO:把camera换成camera2接口??
public class ChrisActivity extends Activity implements SurfaceHolder.Callback{private static final String TAG = "ChrisAcvitity";private Camera mCamera;private SurfaceHolder mHolder;private SurfaceView mView;@Override// 创建Activity时执行的动作protected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.surfaceview_main);mView = (SurfaceView) findViewById(R.id.surfaceView);mHolder = mView.getHolder();mHolder.addCallback(this);}@Override// apk暂停时执行的动作:把相机关闭,避免占用导致其他应用无法使用相机protected void onPause() {super.onPause();mCamera.setPreviewCallback(null);mCamera.stopPreview();mCamera.release();mCamera = null;}@Override// 恢复apk时执行的动作protected void onResume() {super.onResume();if (null!=mCamera){mCamera = getCameraInstance();try {mCamera.setPreviewDisplay(mHolder);mCamera.startPreview();} catch(IOException e) {Log.d(TAG, "Error setting camera preview: " + e.getMessage());}}}// SurfaceHolder.Callback必须实现的方法public void surfaceCreated(SurfaceHolder holder){mCamera = getCameraInstance();try {mCamera.setPreviewDisplay(holder);mCamera.startPreview();} catch(IOException e) {Log.d(TAG, "Error setting camera preview: " + e.getMessage());}}// SurfaceHolder.Callback必须实现的方法public void surfaceChanged(SurfaceHolder holder, int format, int width, int height){refreshCamera(); // 这一步是否多余?在以后复杂的使用场景下,此步骤是必须的。int rotation = getDisplayOrientation(); //获取当前窗口方向mCamera.setDisplayOrientation(rotation); //设定相机显示方向}// SurfaceHolder.Callback必须实现的方法public void surfaceDestroyed(SurfaceHolder holder){mHolder.removeCallback(this);mCamera.setPreviewCallback(null);mCamera.stopPreview();mCamera.release();mCamera = null;}// === 以下是各种辅助函数 ===// 获取camera实例public static Camera getCameraInstance(){Camera c = null;try {c = Camera.open();} catch(Exception e){Log.d("TAG", "camera is not available");}return c;}// 获取当前窗口管理器显示方向private int getDisplayOrientation(){WindowManager windowManager = getWindowManager();Display display = windowManager.getDefaultDisplay();int rotation = display.getRotation();int degrees = 0;switch (rotation){case Surface.ROTATION_0:degrees = 0;break;case Surface.ROTATION_90:degrees = 90;break;case Surface.ROTATION_180:degrees = 180;break;case Surface.ROTATION_270:degrees = 270;break;}android.hardware.Camera.CameraInfo camInfo =new android.hardware.Camera.CameraInfo();android.hardware.Camera.getCameraInfo(Camera.CameraInfo.CAMERA_FACING_BACK, camInfo);// 这里其实还是不太懂:为什么要获取camInfo的方向呢?相当于相机标定??int result = (camInfo.orientation - degrees + 360) % 360;return result;}// 刷新相机private void refreshCamera(){if (mHolder.getSurface() == null){// preview surface does not existreturn;}// stop preview before making changestry {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 settingstry {mCamera.setPreviewDisplay(mHolder);mCamera.startPreview();} catch (Exception e) {}}}

AndroidManifest.xml 记得添加相机权限

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"package="com.example.chris.myapplication" ><uses-permission android:name="android.permission.CAMERA" /><uses-feature android:name="android.hardware.camera" /><uses-feature android:name="android.hardware.camera.autofocus" /><applicationandroid:allowBackup="true"android:icon="@mipmap/ic_launcher"android:label="@string/app_name"android:supportsRtl="true"android:theme="@style/AppTheme" ><activity android:name=".ChrisActivity" ><intent-filter><action android:name="android.intent.action.MAIN" /><category android:name="android.intent.category.LAUNCHER" /></intent-filter></activity></application></manifest>

Android实时取景:用SurfaceView实现相关推荐

  1. android surface编程,Android编程之SurfaceView实例详解

    本文实例讲述了Android编程之SurfaceView用法.分享给大家供大家参考,具体如下: 关于surfaceView相关知识: View和SurfaceView主要区别: 1. View只能在U ...

  2. Android中的SurfaceView详解

    Android中提供了View进行绘图处理,View可以满足大部分的绘图需求,但是有时候,View却显得力不从心,所以Android提供了SurfaceView给Android开发者,以满足更多的绘图 ...

  3. android之利用surfaceView实现自定义水印相机

    android之利用surfaceView实现自定义水印相机 知识点 1.自定义相机+预览相机 2.截屏拍照加水印 3.关于不使用intent来传输图片 4.关于大家说要demo的,因为这里是项目里头 ...

  4. Android截屏SurfaceView黑屏问题解决办法

    Android截屏SurfaceView黑屏问题解决办法 参考文章: (1)Android截屏SurfaceView黑屏问题解决办法 (2)https://www.cnblogs.com/kongyf ...

  5. 采用Android的MediaPlayer+SurfaceView设计视频播放器

    前言 android视频播放有很多方式(自带videoView等),这里简单说其中一种:MediaPlayer+SurfaceView,一个播放音频,一个播放视频(图像). 大体结构图 BaseMed ...

  6. Android CameraSurfaceView在SurfaceView上实现拍照,视频录像

    实现拍照录像功能我们选择SurfaceView,利用android原生API进行拍,录像.满足简单的功能需求.无需继承第三方类库. import android.content.Context; im ...

  7. Android播放器之SurfaceView与GLSurfaceView

    先看Surface Surface的官方介绍:Handle onto a raw buffer that is being managed by the screen compositor,Surfa ...

  8. android Surface和SurfaceView概述

    android.view.Surface概述 翻译至android.view.Surface surface专门用来处理屏幕排版器(screen compositor)管理的一块原始内存(raw bu ...

  9. [转]Android中在SurfaceView上高效绘图

    本文转自:http://hi.baidu.com/fqlibra/blog/item/0216d603876345c07b89478c.html Android的大多数控件都是继承自View的,因此在 ...

最新文章

  1. STM8L之外部中断
  2. mybatis一对多关联查询_一对一,一对多,多对多查询及延迟加载(N+1问题)分析
  3. 有机食品海报这样设计,收获了意想不到的效果…
  4. pbs分解_产品分解结构
  5. idea2020.2中@test是怎么测试的_Sklearn 划分训练集和测试集
  6. YAML_06 playbook从上往下顺序执行,若报错,不提示,继续往下执行
  7. win10 没有计算机策略,Win10家庭版没有组策略怎么办
  8. 基于MyEclipse+JSP+Mysql+Tomcat开发得塞北村镇旅游网站设计
  9. Word怎么删除空白页?6个方法随便用!
  10. littlevgl技术参考手册_树莓派littlevGL系列教程:littlevGL简单了解
  11. elasticsearch从入门到入门系列(一)---简单介绍及安装
  12. xml方式导出word优缺点:
  13. 【MySQL】联合索引的使用
  14. 我的开源项目,趣享GIF源代码已正式公开
  15. 隐私计算与区块链的融合思考
  16. 百度翻译api设置 java_Java调用百度API实现翻译
  17. AE渲染后的视频文件播放时很卡,不流畅
  18. HR面试题(史上最全、持续更新、吐血推荐)
  19. Oracle数据库增加表空间
  20. 实用的3D建模软件:Metasequoia for Mac

热门文章

  1. 火热物联网下,中国传感器的冷思考
  2. VR变革已来!华为完成业界首个5G实验网下Cloud VR业务验证
  3. 机器学习必知的8大神经网络架构和原理
  4. 德国图宾根大学发布可扩展「对抗黑盒攻击」,仅通过观察决策即可愚弄深度神经网络
  5. CCF大数据专家委:2018年大数据发展趋势预测
  6. 苹果损失超 1000 万美元,前员工被控收回扣、盗窃、欺诈!
  7. 你敢参与,我就敢送!牛转好运来,新春大抽奖
  8. vmware 上部署 kvm虚拟机
  9. Java 初始化顺序
  10. p2148 [SDOI2009]ED