android videoview和surfaceview的区别

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了android videoview和surfaceview的区别相关的知识,希望对你有一定的参考价值。

参考技术A   SurfaceView是从View基类中派生出来的显示类,直接子类有GLSurfaceView和VideoView,可以看出GL和视频播放以及Camera摄像头一般均使用SurfaceView,到底有哪些优势呢? SurfaceView可以控制表面的格式,比如大小,显示在屏幕中的位置,最关键是的提供了SurfaceHolder类,使用getHolder方法获取,相关的有Canvas lockCanvas()
  Canvas lockCanvas(Rect dirty) 、void removeCallback(SurfaceHolder.Callback callback)、void unlockCanvasAndPost(Canvas canvas) 控制图形以及绘制,而在SurfaceHolder.Callback 接口回调中可以通过重写下面方法实现。

  使用的SurfaceView的时候,一般情况下要对其进行创建,销毁,改变时的情况进行监视,这就要用到 SurfaceHolder.Callback.
  class XxxView extends SurfaceView implements SurfaceHolder.Callback

  public void surfaceChanged(SurfaceHolder holder,int format,int width,int height)
  //看其名知其义,在surface的大小发生改变时激发
  public void surfaceCreated(SurfaceHolder holder)
  //同上,在创建时激发,一般在这里调用画图的线程。
  public void surfaceDestroyed(SurfaceHolder holder)
  //同上,销毁时激发,一般在这里将画图的线程停止、释放。

  

  对于Surface相关的,Android底层还提供了GPU加速功能,所以一般实时性很强的应用中主要使用SurfaceView而不是直接从View构建,同时后来做android 3d OpenGL中的GLSurfaceView也是从该类实现。

  SurfaceView和View最本质的区别在于,surfaceView是在一个新起的单独线程中可以重新绘制画面而View必须在UI的主线程中更新画面。
  那么在UI的主线程中更新画面 可能会引发问题,比如你更新画面的时间过长,那么你的主UI线程会被你正在画的函数阻塞。那么将无法响应按键,触屏等消息。
  当使用surfaceView 由于是在新的线程中更新画面所以不会阻塞你的UI主线程。但这也带来了另外一个问题,就是事件同步。比如你触屏了一下,你需要surfaceView中thread处理,一般就需要有一个event queue的设计来保存touch event,这会稍稍复杂一点,因为涉及到线程同步。

  所以基于以上,根据游戏特点,一般分成两类。

  1 被动更新画面的。比如棋类,这种用view就好了。因为画面的更新是依赖于 onTouch 来更新,可以直接使用 invalidate。 因为这种情况下,这一次Touch和下一次的Touch需要的时间比较长些,不会产生影响。

  2 主动更新。比如一个人在一直跑动。这就需要一个单独的thread不停的重绘人的状态,避免阻塞main UI thread。所以显然view不合适,需要surfaceView来控制。
  
  3.Android中的SurfaceView类就是双缓冲机制。因此,开发游戏时尽量使用SurfaceView而不要使用View,这样的话效率较高,而且SurfaceView的功能也更加完善。
  
  考虑以上几点,所以我一直都选用 SurfaceView 来进行游戏开发。
  那么在以后源码实例中,我都会以继承sarfaceView框架来进行演示。下一章将详细剖析sarfaceview ,以及附上本人写的游戏开发架构

SurfaceView/VideoView

参考技术A 我们经常用SurfaceView和VideoView来播放视频,但是这两个东东,经常都会出问题。

①SurfaceView不会添加到View树上,并且显示在所有View之上
②在按Home键的时候,会让Surface销毁,并且在重新进入APP的时候,让Surface重建,在Surface重建的时候,SurfaceView那一块是透明的,显示的会是Activity的背景
③如果是列表中的子view中播放视频,在上下滑动的时候,会导致Surface绘制不及时,会有残留
④多个VideoView同时播放的时候,在SurfaceFlinger支持不好的手机上,会出现下一个SurfaceView的某一帧会显示在上一个SurfaceView上

①VideoView是直接继承SurfaceView
②VideoView中的openVideo可能会ANR
③VideoView中的release,stopPlayBack都会导致ANR,因为这些方法都是同步执行的,并且通过IPC服务交给MediaServer去释放资源
解决方法:
使用TextureView替换SurfaceView实现VideoView,因为TextureView是直接继承View的,并且在ListView中滑动的时候,也不会在滑动的时候,有帧残留

当我们有一个列表,每个子项就是一个视频,并且自动播放。surfaceView使用的就是Android自带的状态机来控制播放,所以就会一段一段的将视频先读到缓冲区,再播放。由于MediaPlayer中的release,reset,stopPlayBack都是同步的。而且当视频卡片在滑出屏幕之后,需要把视频暂停,在不可见的时候不进行播放。节省系统资源,并且节省用户流量。而如果同时出现多个视频的时候,会频繁调用到上述生命周期方法,导致很容易出现ANR。
解决方法:
问题1.在视频划出ListView的时候,停止播放视频。
解决方案:在ListView中调用setRecycleListener,设置View回收的监听,因为ListView的重用性,会在View回收到scrap区的时候,通过这个Listener进行一些处理,所以在这里根据View.getTag,找到视频View的引用,调用stopPlayBack停止

问题2.频繁调用release等方法导致ANR
解决方案:在视频调用的时候,建立一个释放视频资源的守护线程。在Android中,直接可以用HandlerThread,因为这样可以尽可能的让资源的消耗达到最少,HandlerThread在没有新事件到来的时候,都是处于wait状态,直到有新事件的到来,才会被notify,处理新事件。它里面也是通过一个Thread,在这个Thread中新建一个Looper,在Looper中没有事件的话,则wait,一旦通过Handler发送新事件的话,则会被notify。所以会在子线程中加入一个队列,当需要release的MediaPlayer,直接丢到子线程去进行资源释放。
但是这样会导致一个问题,就是Android维护的MediaPlayer的状态机中的状态可能会乱,这时候就会抛出IllegalStateException,目前对于这种异常,我们选择了捕获它。

另外,由于MediaPlayer.setSurface需要传递一个Surface,然后再在这个Surface上进行绘制,如果频繁new Surface传入的话,就会导致GrafficBuffer分配Surface失败,从而MediaPlayer会回调onError中,显示视频不能播放。所以尽可能一个视频View用一个Surface。

以上是关于android videoview和surfaceview的区别的主要内容,如果未能解决你的问题,请参考以下文章

SurfaceView/VideoView

VideoView 无法播放视频

启动新 Activity 时保持 VideoView 的状态

android 修改videoview的宽度和高度

android中的VideoView和TextureView和Suraceview有啥区别?

Android中的MediaPlayer和VideoView有啥区别