介绍
我们知道View是通过刷新来重绘视图,系统通过发出VSSYNC信号来进行屏幕的重绘,刷新的时间间隔是16ms,如果我们可以在16ms以内将绘制工作完成,则没有任何问题,如果我们绘制过程逻辑很复杂,并且我们的界面更新还非常频繁,这时候就会造成界面的卡顿,影响用户体验,为此Android提供了SurfaceView来解决这一问题。
SurfaceView 拥有独立的绘图表面,即它不与其宿主窗口共享同一个绘图表面。由于拥有独立的绘图表面,因此SurfaceView的UI就可以在一个独立的线程中进行绘制。又由于不会占用主线程资源,SurfaceView 一方面可以实现复杂而高效的UI,另一方面又不会导致用户输入得不到及时响应。
我们知道普通的 Android 控件,例如 TextView、Button 等,它们都是将自己的UI绘制在宿主窗口的绘图表面之上,这意味着它们的UI是在应用程序的主线程中进行绘制的。一般来说,每一个窗口在SurfaceFlinger服务中都对应有一个Layer,用来描述它的绘图表面。对于那些具有SurfaceView的窗口来说,每一个SurfaceView在SurfaceFlinger服务中还对应有一个独立的Layer或者LayerBuffer,用来单独描述它的绘图表面,以区别于它的宿主窗口的绘图表面。SurfaceFlinger 服务把所有的 LayerBuffer 和 Layer 都抽象为 LayerBase,因此就可以用统一的流程来绘制和合成它们的UI。
上图中 Activity 的 DecorView 及其中的两个TextView控件的UI都是绘制在 SurfaceFlinger 服务中的同一个Layer上面的,而 SurfaceView 的 UI 是绘制在 SurfaceFlinger 服务中的另外一个 Layer 或者 LayerBuffer 上的。
注意,用来描述SurfaceView的Layer或者LayerBuffer的Z轴位置是小于用来其宿主Activity窗口的Layer的Z轴位置的,但是前者会在后者的上面挖一个“洞”出来,以便它的UI可以对用户可见。实际上,SurfaceView在其宿主Activity窗口上所挖的“洞”只不过是在其宿主Activity窗口上设置了一块透明区域。
用法
public class SurfaceViewDemo extends SurfaceView implements SurfaceHolder.Callback, Runnable {
public SurfaceViewTemplate(Context context) {
this(context, null);
//在三个参数的构造方法中完成初始化操作
initView();
}
public SurfaceViewTemplate(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public SurfaceViewTemplate(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
private void initView(){
mSurfaceHolder = getHolder();
//注册回调方法
mSurfaceHolder.addCallback(this);
//设置一些参数方便后面绘图
setFocusable(true);
setKeepScreenOn(true);
setFocusableInTouchMode(true);
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
//创建
new Thread(this).start();
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
//改变
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
//销毁
}
@Override
public void run() {
//子线程
}
}
<com.example.view.SurfaceViewDemo
android:layout_width="match_parent"
android:layout_height="match_parent" />
原理图
SurfaceView.jpg其中有部分方法已修改,需要日后验证
网友评论