首先我们知道View类如果需要更新视图,必须我们主动的去调用invalidate()或者postInvalidate()方法来再走一次onDraw()完成更新。但是呢,Android系统规定屏幕的刷新间隔为16ms,如果这个View在16ms内更新完毕了,就不会卡顿,但是如果逻辑操作太多,16ms内没有更新完毕,剩下的操作就会丢到下一个16ms里去完成,这样就会造成UI线程的阻塞,造成View的运动过程掉帧,自然就会卡顿了。
所以这些原因也就促使了SurfaceView的存在。比如一个Camera,它有可能相当频繁的有更新画面的需求。

(1)简单介绍

(A)SurfaceView

它继承自View,因此它本质上是一个View。但与普通View不同的是,它有自己的Surface。
一般的Activity包含的多个View会组成View hierachy的树形结构,只有最顶层的DecorView,也就是根结点视图,才是对WMS可见的。这个DecorView在WMS中有一个对应的WindowState。相应地,在SF中有对应的Layer。

这样的好处是对这个Surface的渲染可以放到单独线程去做,它不会影响主线程对事件的响应。但它也有缺点,因为这个Surface不在View hierachy中,它的显示也不受View的属性控制,所以不能进行平移,缩放等变换,也不能放在其它ViewGroup中,一些View中的特性也无法使用。

  • SurfaceView中采用了双缓冲机制,保证了UI界面的流畅性,同时 SurfaceView 不在主线程中绘制,而是另开辟一个线程去绘制,所以它不妨碍UI线程;
  • View底层没有双缓冲机制,SurfaceView有;
  • view主要适用于主动更新,而SurfaceView适用与被动的更新,如频繁的刷新;
  • view会在主线程中去更新UI,而SurfaceView则在子线程中刷新;
  • SurfaceView的内容不在应用窗口上,所以不能使用变换(平移、缩放、旋转等)。也难以放在ListView或者ScrollView中,不能使用UI控件的一些特性比如View.setAlpha();

(B)TextureView

与SurfaceView相比,TextureView并没有创建一个单独的Surface用来绘制,因此可以和其它普通View一样进行移动,旋转,缩放,动画等变化。另外,Textureview必须在硬件加速开启的窗口中;

从类图中可以看到,TextureView继承自View,它与其它的View一样在View hierachy中管理与绘制。TextureView重载了draw()方法,其中主要SurfaceTexture中收到的图像数据作为纹理更新到对应的HardwareLayer中。

SurfaceTexture.OnFrameAvailableListener用于通知TextureView内容流有新图像到来。TextureView.SurfaceTextureListener接口用于让TextureView的使用者知道SurfaceTexture已准备好,这样就可以把SurfaceTexture交给相应的内容源。

  • 支持移动、旋转、缩放等动画,支持截图;
  • 必须在硬件加速的窗口中使用,占用内存比SurfaceView高,在5.0以前在主线程渲染,5.0以后有单独的渲染线程;

(C)SurfaceTexture

SurfaceTexture用来捕获视频流(stream)中的图像帧(image frame)的,视频流可以是相机预览或者视频解码数据。SurfaceTexture可以作为android.hardware.camera2、MediaCodec、MediaPlayer、和 VideoDecode这些类的目标视频数据输出对象。

SurfaceTexture和SurfaceView不同的是,它对图像流的处理并不直接显示,而是转为OpenGL的外部纹理,因此可用于图像流数据的二次处理(如Camera滤镜,桌面特效等)。比如Camera的预览数据,可以通过SurfaceTexture交给TextureView作为View heirachy中的一个硬件加速层来显示。首先,SurfaceTexture从图像流(来自Camera预览,视频解码,GL绘制场景等)中获得帧数据,当SurfaceTexture中有数据帧更新时,SurfaceTexture.OnFrameAvailableListener这个监听接口将会有回调,此时可以调用updateTexImage()方法从视频流数据中更新当前数据帧。并通过SurfaceTexture所绑定的OpenGL纹理对象来对其进行一些图像处理操作。

(2)API相关

(A)Surface

//android.view.SurfaceROTATION_0
ROTATION_90
ROTATION_180
ROTATION_270Surface(SurfaceTexture surfaceTexture)Canvas    lockCanvas(Rect inOutDirty)
Canvas  lockHardwareCanvas()
void    unlockCanvasAndPost(Canvas canvas)

(B)SurfaceView

//android.view.View
//     ↳    android.view.SurfaceViewvoid    draw(Canvas canvas)
SurfaceHolder   getHolder()
void    setZOrderMediaOverlay(boolean isMediaOverlay)
void    setZOrderOnTop(boolean onTop)onMeasure(int widthMeasureSpec, int heightMeasureSpec)

(C)SurfaceHolder

//android.view.SurfaceHolderSurfaceHolder.Callbackabstract void  surfaceChanged(SurfaceHolder holder, int format, int width, int height)abstract void    surfaceCreated(SurfaceHolder holder)abstract void   surfaceDestroyed(SurfaceHolder holder)abstract void addCallback(SurfaceHolder.Callback callback)
abstract Surface    getSurface()
abstract Canvas lockCanvas()
default Canvas  lockHardwareCanvas()
abstract void   removeCallback(SurfaceHolder.Callback callback)
abstract void   setFixedSize(int width, int height)
abstract void   setFormat(int format)
abstract void   setKeepScreenOn(boolean screenOn)
abstract void   setSizeFromLayout()
abstract void   unlockCanvasAndPost(Canvas canvas)

(D)TextureView

//android.view.View
//     ↳    android.view.TextureViewTextureView.SurfaceTextureListenerabstract void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height)abstract boolean    onSurfaceTextureDestroyed(SurfaceTexture surface)abstract void  onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height)abstract void onSurfaceTextureUpdated(SurfaceTexture surface)final void   draw(Canvas canvas)
Bitmap  getBitmap(int width, int height)
Bitmap  getBitmap()
Bitmap  getBitmap(Bitmap bitmap)SurfaceTexture  getSurfaceTexture()
void    setSurfaceTexture(SurfaceTexture surfaceTexture)
TextureView.SurfaceTextureListener  getSurfaceTextureListener()
void    setSurfaceTextureListener(TextureView.SurfaceTextureListener listener)Matrix    getTransform(Matrix transform)
void    setTransform(Matrix transform)Canvas    lockCanvas()
void    unlockCanvasAndPost(Canvas canvas)final void    onDraw(Canvas canvas)
void    onSizeChanged(int w, int h, int oldw, int oldh)
void    onVisibilityChanged(View changedView, int visibility)

(E)SurfaceTexture

//android.graphics.SurfaceTextureSurfaceTexture.OnFrameAvailableListenerabstract void    onFrameAvailable(SurfaceTexture surfaceTexture)long getTimestamp()
void    getTransformMatrix(float[] mtx)
void    setDefaultBufferSize(int width, int height)
void    setOnFrameAvailableListener(SurfaceTexture.OnFrameAvailableListener listener)
void    updateTexImage()
void    releaseTexImage()

(3)Demo

(A)自定义PreviewSurfaceView

import android.content.Context;
import android.content.res.Configuration;
import android.graphics.Point;
import android.util.AttributeSet;
import android.view.Display;
import android.view.SurfaceView;
import android.view.WindowManager;public class PreviewSurfaceView extends SurfaceView {private static final double ASPECT_TOLERANCE = 0.03;private double mAspectRatio = 0.0;private int mPreviewWidth = 0;private int mPreviewHeight = 0;public PreviewSurfaceView(Context context, AttributeSet attrs) {super(context, attrs);}public void setAspectRatio(double aspectRatio) {if (mAspectRatio != aspectRatio) {mAspectRatio = aspectRatio;requestLayout();}}@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {int previewWidth = MeasureSpec.getSize(widthMeasureSpec);int previewHeight = MeasureSpec.getSize(heightMeasureSpec);boolean widthLonger = previewWidth > previewHeight;int longSide = (widthLonger ? previewWidth : previewHeight);int shortSide = (widthLonger ? previewHeight : previewWidth);if (mAspectRatio > 0) {double fullScreenRatio = findFullscreenRatio(getContext());if (Math.abs((mAspectRatio - fullScreenRatio)) <= ASPECT_TOLERANCE) {// full screen preview caseif (longSide < shortSide * mAspectRatio) {longSide = Math.round((float) (shortSide * mAspectRatio) / 2) * 2;} else {shortSide = Math.round((float) (longSide / mAspectRatio) / 2) * 2;}} else {// standard (4:3) preview caseif (longSide > shortSide * mAspectRatio) {longSide = Math.round((float) (shortSide * mAspectRatio) / 2) * 2;} else {shortSide = Math.round((float) (longSide / mAspectRatio) / 2) * 2;}}}if (widthLonger) {previewWidth = longSide;previewHeight = shortSide;} else {previewWidth = shortSide;previewHeight = longSide;}boolean originalPreviewIsLandscape = (mPreviewWidth > mPreviewHeight);boolean configurationIsLandscape =(getContext().getResources().getConfiguration().orientation ==Configuration.ORIENTATION_LANDSCAPE);// if configuration is changed, swap to view's configuration//  if (originalPreviewIsLandscape != configurationIsLandscape) {//  int originalPreviewWidth = previewWidth;// previewWidth = previewHeight;// previewHeight = originalPreviewWidth;// }setMeasuredDimension(previewWidth, previewHeight);}protected boolean isFullScreenPreview(double aspectRatio) {double fullScreenRatio = findFullscreenRatio(getContext());if (Math.abs((aspectRatio - fullScreenRatio)) <= ASPECT_TOLERANCE) {return true;} else {return false;}}private static double findFullscreenRatio(Context context) {WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);Display display = wm.getDefaultDisplay();Point point = new Point();display.getRealSize(point);double fullscreen;if (point.x > point.y) {fullscreen = (double) point.x / point.y;} else {fullscreen = (double) point.y / point.x;}return fullscreen;}
}

(B)自定义PreviewTextureView

import android.content.Context;
import android.graphics.Point;
import android.util.AttributeSet;
import android.view.Display;
import android.view.TextureView;
import android.view.WindowManager;public class PreviewTextureView extends TextureView {private static final double ASPECT_TOLERANCE = 0.03;private double mAspectRatio = 0.0;public PreviewTextureView(Context context) {this(context, null);}public PreviewTextureView(Context context, AttributeSet attrs) {this(context, attrs, 0);}public PreviewTextureView(Context context, AttributeSet attrs, int defStyle) {super(context, attrs, defStyle);}public void setAspectRatio(double aspectRatio) {if (mAspectRatio != aspectRatio) {mAspectRatio = aspectRatio;requestLayout();}}@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {int previewWidth = MeasureSpec.getSize(widthMeasureSpec);int previewHeight = MeasureSpec.getSize(heightMeasureSpec);boolean widthLonger = previewWidth > previewHeight;int longSide = (widthLonger ? previewWidth : previewHeight);int shortSide = (widthLonger ? previewHeight : previewWidth);if (mAspectRatio > 0) {double fullScreenRatio = findFullscreenRatio(getContext());if (Math.abs((mAspectRatio - fullScreenRatio)) <= ASPECT_TOLERANCE) {// full screen preview caseif (longSide < shortSide * mAspectRatio) {longSide = Math.round((float) (shortSide * mAspectRatio) / 2) * 2;} else {shortSide = Math.round((float) (longSide / mAspectRatio) / 2) * 2;}} else {// standard (4:3) preview caseif (longSide > shortSide * mAspectRatio) {longSide = Math.round((float) (shortSide * mAspectRatio) / 2) * 2;} else {shortSide = Math.round((float) (longSide / mAspectRatio) / 2) * 2;}}}if (widthLonger) {previewWidth = longSide;previewHeight = shortSide;} else {previewWidth = shortSide;previewHeight = longSide;}setMeasuredDimension(previewWidth, previewHeight);}private static double findFullscreenRatio(Context context) {WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);Display display = wm.getDefaultDisplay();Point point = new Point();display.getRealSize(point);double fullscreen;if (point.x > point.y) {fullscreen = (double) point.x / point.y;} else {fullscreen = (double) point.y / point.x;}return fullscreen;}
}

(C)SurfaceView Demo

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent" ><SurfaceViewandroid:id="@+id/surfaceView"android:layout_width="match_parent"android:layout_height="match_parent"/>
</RelativeLayout>
private void getScreenParams() {DisplayMetrics dm = new DisplayMetrics();// 获取屏幕信息getWindowManager().getDefaultDisplay().getMetrics(dm);screenWidth = dm.widthPixels;screenHeight = dm.heightPixels;}protected void initView() {surfaceHolder = surfaceview.getHolder();surfaceHolder.setKeepScreenOn(true);surfaceHolder.addCallback(new SurfaceViewCallback());// 调整surfaceView的大小ViewGroup.LayoutParams params = surfaceview.getLayoutParams();params.width = screenWidth;params.height = screenHeight;surfaceview.setLayoutParams(params);}private class SurfaceViewCallback implements SurfaceHolder.Callback {@Overridepublic void surfaceChanged(SurfaceHolder holder, int format, int width,int height) {mCamera.setPreviewDisplay(holder);mCamera.startPreview();}@Overridepublic void surfaceCreated(SurfaceHolder holder) {}@Overridepublic void surfaceDestroyed(SurfaceHolder holder) {}}

(D)TextureView Demo

public class LiveCameraActivity extends Activity implements TextureView.SurfaceTextureListener {private Camera mCamera;private TextureView mTextureView;protected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);mTextureView = new TextureView(this);mTextureView.setSurfaceTextureListener(this);setContentView(mTextureView);}public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {mCamera = Camera.open();try {mCamera.setPreviewTexture(surface);mCamera.startPreview();} catch (IOException ioe) {// Something bad happened}}public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {}public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {mCamera.stopPreview();mCamera.release();return true;}public void onSurfaceTextureUpdated(SurfaceTexture surface) {}}

(4)总结

  • SurfaceView是一个有自己独立Surface的View, 它的渲染可以放在单独线程而不是主线程中, 其缺点是不能做变形和动画;
  • SurfaceTexture可以用作非直接输出的内容流,这样就提供二次处理的机会。与SurfaceView直接输出相比,这样会有若干帧的延迟;
  • TextureView是一个可以把内容流作为外部纹理输出在上面的View, 它本身需要是一个硬件加速层;

SurfaceView,TextureView,SurfaceTexture相关相关推荐

  1. TextureView+SurfaceTexture+OpenGL ES来播放视频(一)

    前言 最近发现视频直播类应用层出不穷,比如233手游直播,蓝鲸直播,微录客等等什么的,连android界大神老罗也在开发手游录制类的应用,这里面的技术含量也是挺高的,需要了解android 系统的UI ...

  2. Android 笔记 surfaceView textureView

    SurfaceView Android有一个组件叫SurfaceView,是一个单独的组件,但是并不是和其他常见组件一样提供特别的功能(比如图片浏览,输入字符等等),就是一个空组件.那么这个有什么用呢 ...

  3. 如何解决和异地女朋友一起看电影的需求?(内附源码)

    一.这是一件悲伤的故事 我是一名程序员,我和我的女友是异地恋,so sad!!! 一次视频时,她突然来了一句:"我们已经很久没有一起看电影了吧......" "呃...好 ...

  4. 使用OES纹理+GLSurfaceView+JNI实现基于OpenGL ES的播放器画面处理

    前言: 安卓使用SurfaceView + SurfaceTexture + Surface进行视频播放或者相机预览,只能看到原色画面,但很多场合需求画面可以实现二次加工,例如调整红绿蓝三原色的比例. ...

  5. 超简单!Android 播放流媒体

    简介 我利用了大名鼎鼎的vlc来播放媒体.它可以播放来自网络.摄像头.磁盘.光驱的文件,支持包括MPEG 1/2/4, H264, VC-1, DivX, WMV, Vorbis, AC3, AAC等 ...

  6. 你了解视频 API 吗?

    本文介绍什么是视频 API?视频API如何保证音视频的流畅传输? 什么是视频 API? Video API是专门提供音视频传输服务的接口,主要分为静态视频API和直播视频API两种. 静态视频 API ...

  7. 浅谈 SurfaceView、TextureView、GLSurfaceView、SurfaceTexture

    一.SurfaceView SurfaceView 是一个可以在子线程中更新 UI 的 View,且不会影响到主线程.它为自己创建了一个窗口(window),就好像在视图层次(View Hierarc ...

  8. Android openGl开发详解(二)——通过SurfaceView,TextureView,GlSurfaceView显示相机预览(附Demo)

    最近公司在做自定义相机这一块,之前使用的是第三方,后来需求变更,第三方不支持添加动态贴纸,所以只能自己扩展.当然网上有很多例子,但是关于添加动态贴纸的例子几乎找不到,反正我是没找到(欲哭无泪).当然, ...

  9. SurfaceView 与 TextureView 详解

    前言 播放视频或者渲染其他的动画的时候,有两个 View 组件可供选择,SurfaceView 和 TextureView,GLSurfaceView 是 SurfaceView 的子类,在 Surf ...

最新文章

  1. Current综述:中农宋春旭等为植物有益微生物组构建一个美好家园
  2. Only Available on April 1st
  3. css涟漪光圈扩散_CSS动画实例:圆的涟漪扩散
  4. 最长回文子串Python解法
  5. 零成本兼职副业有哪些?
  6. Dorado Debugger工具
  7. nyist 2 括号配对问题
  8. android studio for android learning (六)应用程序窗体显示状态操作(requestWindowFeature等的应用)
  9. python用turtle画一个苹果
  10. python 二项分布_Python模拟伯努利试验和二项分布代码实例
  11. 打印目录和更新时就会出现“错误!未定义书签!”的解决技巧
  12. Vue 九宫格抽奖实现
  13. 《伯克毕生发展心理学2》
  14. 7月的尾巴,你是XXX
  15. 人体红外传感器和光敏传感器检测问题
  16. 转:英语 表示字母、数字的复数
  17. kindle电子书资源搜索及制作教程
  18. 支付宝面对面支付(境外)
  19. Ubuntu操作系统输入法键位错乱解法记录(输入法无法正确打出~、等字符)
  20. WPS JS宏示例——工作表排序

热门文章

  1. Linux之shell数组
  2. 大话 java android 接口回调 全面解析点击事件 大量举例
  3. Implicitly declaring library function ‘malloc‘ with type ‘void *(unsigned long)‘
  4. 百分位数的计算原理--NumPy数组实现
  5. 【Latex】Latex小白入门(2)——如何用.bib文件自动生成论文Reference
  6. 李笑来~执行力WWH
  7. Mysql数据迁移到SqlServer
  8. 未来的什么行业最赚钱?
  9. ubuntu系统引导修复
  10. python操作MongoDB数据库(1)查询