SurfaceControlViewHost
是Android 11中加入的一个新工具类,其在Google文档中的描述如下:
Utility class for adding a View hierarchy to a
[SurfaceControl](https://developer.android.com/reference/android/view/SurfaceControl)
. The View hierarchy will render in to a root SurfaceControl, and receive input based on the SurfaceControl's placement on-screen. The primary usage of this class is to embed a View hierarchy from one process in to another. After the SurfaceControlViewHost has been set up in the embedded content provider, we can send the[SurfaceControlViewHost.SurfacePackage](https://developer.android.com/reference/android/view/SurfaceControlViewHost.SurfacePackage)
to the host process. The host process can then attach the hierarchy to a SurfaceView within its own by calling[SurfaceView#setChildSurfacePackage](https://developer.android.com/reference/android/view/SurfaceView#setChildSurfacePackage(android.view.SurfaceControlViewHost.SurfacePackage))
.
简单来说这是一个提供了跨进程UI渲染的工具类,SurfaceControlViewHost
的作用类似于一个特殊的Window
容器。不同的是,这个容器中的View hierarchy
并不是直接在本地的Canvas
上进行绘制,而是绑定到了一个SurfaceView
中,这种绑定是通过Binder
机制实现的,为跨进程使用而设计。
和RemoteViews
这种虚假的跨进城UI机制相比,SurfaceControlViewHost
提供的能力可以说有天壤之别。
1,SurfaceControlViewHost
支持所有的View
子类,包括开发者在本地自定义的控件,支持使用任何定义在本地的资源。
2,SurfaceControlViewHost
支持触摸事件传递,开发者可以直接使用View.onClickListener
和dispatchMotionEvent
等熟悉的机制完成复杂的交互开发。
3,SurfaceControlViewHost
渲染的性能和在本地Window
中几乎没有区别。
4,SurfaceControlViewHost
绑定使用的SurfacePackage
对象是完全与业务数据无关的,所有的业务逻辑都发生在本地进程,开发者无需担心在远端进程集成功能组件时有安全性问题。
要理解为什么SurfaceControlViewHost
能够提供如此强大的功能,需要我们对Android系统上的渲染机制有一定的了解。我们知道,每个Activity
(或者Dialog
和PopupWindow
)所具有的Window
对象,其实都在WindowManager
的管理下,对应着一个SurfaceFlinger
中的Surface
对象,而Surface
对象的本质,可以简单的理解为一个内存中的绘制缓存区,代表了一个可以绘制的图层。系统渲染时,首先通过Canvas
记录了所有绘制数据,再传递给SurfaceFlinger
在图层上做实际的绘制计算,然后再将其合成为真正的屏幕帧。
同时我们知道,SurfaceView
是一个特殊的控件,它并不在所在Window
上进行绘制,而是具有一个独立的Surface
,用于提供给某些媒体进行渲染(最常见的如视频播放器或者摄像头硬件)。
因此我们知道,渲染的过程本来就是跨进程的,只要能获得一个Surface
的句柄,拥有系统权限的代码就可以直接在这个Surface
对应的图层上进行绘制。而SurfaceControlViewHost
就是这样一个工具,帮助我们将本地的View hierarchy
和远端的SurfaceView
绑定起来,实现跨进程渲染。
说了这么多,可能大家对怎么应用还是一头雾水,这里有一个我写的demo,参考了国外一位大神的文章。
对于这个demo,有以下几点说明:
1,通信方式使用了Messenger
模式,使用aidl
可以得到同样的效果。
2,不支持EditText
唤醒输入法,这个需要自己实现,一个比较简单的替代是点击之后启动一个Activity来获取输入。
3,直接使用SurfaceView.setZOrderOnTop
的方式来传递触摸事件会造成对系统UI的遮挡,因此demo中自行通过binder
传递触摸事件,这样做的一个好处是为将来在远端和本地之间转移事件的处理权提供了灵活性。
网友评论