1 前言
本文将介绍基于 SurfaceControlViewHost 实现跨进程渲染普通 View 和 GlSurfaceView,力求用最简单的 Demo,介绍 SurfaceControlViewHost 的应用,方便读者轻松扣出核心代码应用到自己的业务中。
核心代码片段如下。
1)服务端
public SurfaceControlViewHost.SurfacePackage getSurfacePackage(int displayId, IBinder hostToken, int width, int height) { // 创建SurfaceControlViewHost Display display = mContext.getSystemService(DisplayManager.class).getDisplay(displayId); mSurfaceControlViewHost = new SurfaceControlViewHost(mContext, display, hostToken); // 创建要渲染的View mView = new CustomView(mContext); // 将View附加到SurfaceControlViewHost mSurfaceControlViewHost.setView(mView, width, height); SurfacePackage surfacePackage = mSurfaceControlViewHost.getSurfacePackage(); return surfacePackage; }
2)客户端
IBinder hostToken = mSurfaceView.getHostToken(); SurfaceControlViewHost.SurfacePackage surfacePackage = mRemoteRender.getSurfacePackage(0, hostToken, 1000, 2000); mSurfaceView.setChildSurfacePackage(surfacePackage);
本文案例项目结构如下,完整资源见 → 基于SurfaceControlViewHost实现跨进程渲染。

2 AIDL 配置
Android 跨进程通信可以使用 AIDL 或 messenger,它们本质都是 Binder,本文使用 AIDL 实现跨进程通信。
1)aidl 文件
// IRemoteRender.aidl package com.zhyan8.remoterender; import android.view.SurfaceControlViewHost.SurfacePackage; import android.os.IBinder; interface IRemoteRender { SurfacePackage getSurfacePackage(int displayId, IBinder hostToken, int width, int height); }
2)gradle 配置
sourceSets { main { aidl.srcDirs = ['src/main/aidl'] } } buildFeatures.aidl true
3)manifest 配置
客户端配置如下。
<queries> <package android:name="com.zhyan8.service" /> <package android:name="com.zhyan8.glservice" /> </queries>
服务端配置如下。
<service android:name=".RemoteRenderService" android:exported="true"> <intent-filter> <action android:name="com.zhyan8.remoterender.IRemoteRender"/> </intent-filter> </service> <service android:name=".RemoteGLRenderService" android:exported="true"> <intent-filter> <action android:name="com.zhyan8.remoterender.IRemoteRender"/> </intent-filter> </service>
3 客户端
MainActivity.java
package com.zhyan8.client; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; import android.os.Bundle; import android.os.IBinder; import android.os.RemoteException; import android.util.Log; import android.view.SurfaceControlViewHost.SurfacePackage; import android.view.SurfaceView; import android.view.View; import androidx.appcompat.app.AppCompatActivity; import com.zhyan8.remoterender.IRemoteRender; public class MainActivity extends AppCompatActivity { private static final String TAG = "MainActivity"; private IRemoteRender mRemoteRender; private IBinder mService; private SurfaceView mSurfaceView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mSurfaceView = findViewById(R.id.surface_view); startService(); } public void onClickDraw(View view) { try { IBinder hostToken = mSurfaceView.getHostToken(); SurfacePackage surfacePackage = mRemoteRender.getSurfacePackage(0, hostToken, 1000, 2000); mSurfaceView.setChildSurfacePackage(surfacePackage); } catch (RemoteException e) { e.printStackTrace(); } } @Override protected void onDestroy() { super.onDestroy(); unbindService(mConnection); } private void startService() { Log.d(TAG, "startService"); Intent intent = new Intent("com.zhyan8.remoterender.IRemoteRender"); //intent.setPackage("com.zhyan8.service"); // 渲染普通View的服务 intent.setPackage("com.zhyan8.glservice"); // 基于OpenGL ES渲染的服务 bindService(intent, mConnection, Context.BIND_AUTO_CREATE); } private void clearBind() { Log.d(TAG, "clearBind"); if (mService != null) { mService.unlinkToDeath(mDeathRecipient, 0); } mRemoteRender = null; mService = null; } private ServiceConnection mConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { Log.d(TAG, "onServiceConnected"); mRemoteRender = IRemoteRender.Stub.asInterface(service); mService = service; try { mService.linkToDeath(mDeathRecipient, 0); } catch (RemoteException e) { Log.e(TAG, "e=" + e.getMessage()); } } @Override public void onServiceDisconnected(ComponentName name) { Log.d(TAG, "onServiceDisconnected"); clearBind(); } }; private IBinder.DeathRecipient mDeathRecipient = new IBinder.DeathRecipient() { @Override public void binderDied() { Log.d(TAG, "binderDied"); clearBind(); } }; }
activity_main.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:padding="16dp"> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="draw" android:onClick="onClickDraw"/> <android.view.SurfaceView android:id="@+id/surface_view" android:layout_width="1000px" android:layout_height="2000px" android:layout_gravity="center"/> </LinearLayout>
4 跨进程渲染普通 View
RemoteRenderService.java
package com.zhyan8.service; import android.app.Service; import android.content.Context; import android.content.Intent; import android.hardware.display.DisplayManager; import android.os.Handler; import android.os.IBinder; import android.os.Looper; import android.util.Log; import android.view.Display; import android.view.SurfaceControlViewHost; import android.view.SurfaceControlViewHost.SurfacePackage; import android.view.ViewGroup; import android.widget.ImageView; import com.zhyan8.remoterender.IRemoteRender; import java.util.concurrent.CountDownLatch; public class RemoteRenderService extends Service { private static final String TAG = "RemoteRenderService"; private SurfaceControlViewHost mSurfaceControlViewHost; private ImageView mImageView; private Handler mHandler = new Handler(Looper.getMainLooper()); @Override public void onCreate() { super.onCreate(); Log.i(TAG, "onCreate"); } @Override public IBinder onBind(Intent intent) { Log.i(TAG, "onBind"); return mBinder; } @Override public void onDestroy() { super.onDestroy(); Log.i(TAG, "onDestroy"); if (mSurfaceControlViewHost != null) { mSurfaceControlViewHost.release(); } } private final IRemoteRender.Stub mBinder = new IRemoteRender.Stub() { @Override public SurfacePackage getSurfacePackage(int displayId, IBinder hostToken, int width, int height) { Log.i(TAG, "getSurfacePackage, displayId=" + displayId + ", hostToken=" + hostToken + ", width=" + width + ", height=" + height); final SurfacePackage[] result = new SurfaceControlViewHost.SurfacePackage[1]; final CountDownLatch latch = new CountDownLatch(1); mHandler.post( () -> { // 创建SurfaceControlViewHost Context context = getBaseContext(); Display display = context.getSystemService(DisplayManager.class).getDisplay(displayId); mSurfaceControlViewHost = new SurfaceControlViewHost(context, display, hostToken); // 创建要渲染的内容 mImageView = new ImageView(RemoteRenderService.this); mImageView.setLayoutParams(new ViewGroup.LayoutParams(width, height)); mImageView.setScaleType(ImageView.ScaleType.FIT_XY); mImageView.setImageResource(R.drawable.girl); // 将视图附加到SurfaceControlViewHost mSurfaceControlViewHost.setView(mImageView, width, height); result[0] = mSurfaceControlViewHost.getSurfacePackage(); latch.countDown(); }); try { latch.await(); // 等待主线程完成操作 return result[0]; } catch (InterruptedException e) { Log.i(TAG, "getSurfacePackage, e=" + e.getMessage()); } return null; } }; }
运行效果如下。

5 跨进程渲染 GLSurfaceView
RemoteGLRenderService.java
package com.zhyan8.glservice; import android.app.Service; import android.content.Context; import android.content.Intent; import android.hardware.display.DisplayManager; import android.opengl.GLSurfaceView; import android.os.Handler; import android.os.IBinder; import android.os.Looper; import android.util.Log; import android.view.Display; import android.view.SurfaceControlViewHost; import android.view.SurfaceControlViewHost.SurfacePackage; import android.view.ViewGroup; import com.zhyan8.remoterender.IRemoteRender; import java.util.concurrent.CountDownLatch; public class RemoteGLRenderService extends Service { private static final String TAG = "RemoteGLRenderService"; private SurfaceControlViewHost mSurfaceControlViewHost; private GLSurfaceView mGLSurfaceView; private Handler mHandler = new Handler(Looper.getMainLooper()); @Override public void onCreate() { super.onCreate(); Log.i(TAG, "onCreate"); } @Override public IBinder onBind(Intent intent) { Log.i(TAG, "onBind"); return mBinder; } @Override public void onDestroy() { Log.i(TAG, "onDestroy"); super.onDestroy(); if (mSurfaceControlViewHost != null) { mSurfaceControlViewHost.release(); } } private final IRemoteRender.Stub mBinder = new IRemoteRender.Stub() { @Override public SurfacePackage getSurfacePackage(int displayId, IBinder hostToken, int width, int height) { Log.i(TAG, "getSurfacePackage, displayId=" + displayId + ", hostToken=" + hostToken + ", width=" + width + ", height=" + height); final SurfacePackage[] result = new SurfaceControlViewHost.SurfacePackage[1]; final CountDownLatch latch = new CountDownLatch(1); mHandler.post( () -> { // 创建SurfaceControlViewHost Context context = getBaseContext(); Display display = context.getSystemService(DisplayManager.class).getDisplay(displayId); mSurfaceControlViewHost = new SurfaceControlViewHost(context, display, hostToken); // 创建要渲染的内容 mGLSurfaceView = new GLSurfaceView(RemoteGLRenderService.this); mGLSurfaceView.setEGLContextClientVersion(3); mGLSurfaceView.setLayoutParams(new ViewGroup.LayoutParams(width, height)); mGLSurfaceView.setRenderer(new MyGLRenderer(RemoteGLRenderService.this)); // 将视图附加到SurfaceControlViewHost mSurfaceControlViewHost.setView(mGLSurfaceView, width, height); result[0] = mSurfaceControlViewHost.getSurfacePackage(); latch.countDown(); }); try { latch.await(); // 等待主线程完成操作 return result[0]; } catch (InterruptedException e) { Log.i(TAG, "getSurfacePackage, e=" + e.getMessage()); } return null; } }; }
MyGLRenderer.java
package com.zhyan8.glservice; import android.opengl.GLES30; import android.opengl.GLSurfaceView; import javax.microedition.khronos.egl.EGLConfig; import javax.microedition.khronos.opengles.GL10; import android.content.Context; import java.nio.FloatBuffer; public class MyGLRenderer implements GLSurfaceView.Renderer { private FloatBuffer vertexBuffer; private FloatBuffer textureBuffer; private MyGLUtils mGLUtils; private int mTextureId; private int mTimeLocation; private long mStartTime = 0L; private long mRunTime = 0L; public MyGLRenderer(Context context) { mGLUtils = new MyGLUtils(context); getFloatBuffer(); mStartTime = System.currentTimeMillis(); } @Override public void onSurfaceCreated(GL10 gl, EGLConfig eglConfig) { //设置背景颜色 GLES30.glClearColor(0.1f, 0.2f, 0.3f, 0.4f); //编译着色器 final int vertexShaderId = mGLUtils.compileShader(GLES30.GL_VERTEX_SHADER, R.raw.vertex_shader); final int fragmentShaderId = mGLUtils.compileShader(GLES30.GL_FRAGMENT_SHADER, R.raw.fragment_shader); //链接程序片段 int programId = mGLUtils.linkProgram(vertexShaderId, fragmentShaderId); GLES30.glUseProgram(programId); mTextureId = mGLUtils.loadTexture(R.drawable.girl); mTimeLocation = GLES30.glGetUniformLocation(programId, "u_time"); } @Override public void onSurfaceChanged(GL10 gl, int width, int height) { //设置视图窗口 GLES30.glViewport(0, 0, width, height); } @Override public void onDrawFrame(GL10 gl) { mRunTime = System.currentTimeMillis() - mStartTime; //将颜色缓冲区设置为预设的颜色 GLES30.glClear(GLES30.GL_COLOR_BUFFER_BIT); GLES30.glUniform1f(mTimeLocation, mRunTime / 1000f); //启用顶点的数组句柄 GLES30.glEnableVertexAttribArray(0); GLES30.glEnableVertexAttribArray(1); //准备顶点坐标和纹理坐标 GLES30.glVertexAttribPointer(0, 3, GLES30.GL_FLOAT, false, 0, vertexBuffer); GLES30.glVertexAttribPointer(1, 2, GLES30.GL_FLOAT, false, 0, textureBuffer); //激活纹理 GLES30.glActiveTexture(GLES30.GL_TEXTURE); //绑定纹理 GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, mTextureId); //绘制贴图 GLES30.glDrawArrays(GLES30.GL_TRIANGLE_FAN, 0, 4); //禁止顶点数组句柄 GLES30.glDisableVertexAttribArray(0); GLES30.glDisableVertexAttribArray(1); } private void getFloatBuffer() { float[] vertex = new float[] { 1f, 1f, 0f, //V0 -1f, 1f, 0f, //V1 -1f, -1f, 0f, //V2 1f, -1f, 0f //V3 }; float[] texture = { 1f, 0f, //V0 0f, 0f, //V1 0f, 1.0f, //V2 1f, 1.0f //V3 }; vertexBuffer = mGLUtils.getFloatBuffer(vertex); textureBuffer = mGLUtils.getFloatBuffer(texture); } }
MyGLUtils.java
package com.zhyan8.glservice; import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.opengl.GLES30; import android.opengl.GLUtils; import android.opengl.Matrix; import java.io.BufferedReader; import java.io.InputStream; import java.io.InputStreamReader; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.FloatBuffer; public class MyGLUtils { private Context mContext; private Bitmap mBitmap; public MyGLUtils(Context context) { mContext = context; } public FloatBuffer getFloatBuffer(float[] floatArr) { FloatBuffer fb = ByteBuffer.allocateDirect(floatArr.length * Float.BYTES) .order(ByteOrder.nativeOrder()) .asFloatBuffer(); fb.put(floatArr); fb.position(0); return fb; } //通过代码片段编译着色器 public int compileShader(int type, String shaderCode){ int shader = GLES30.glCreateShader(type); GLES30.glShaderSource(shader, shaderCode); GLES30.glCompileShader(shader); return shader; } //通过外部资源编译着色器 public int compileShader(int type, int shaderId){ String shaderCode = readShaderFromResource(shaderId); return compileShader(type, shaderCode); } //链接到着色器 public int linkProgram(int vertexShaderId, int fragmentShaderId) { final int programId = GLES30.glCreateProgram(); //将顶点着色器加入到程序 GLES30.glAttachShader(programId, vertexShaderId); //将片元着色器加入到程序 GLES30.glAttachShader(programId, fragmentShaderId); //链接着色器程序 GLES30.glLinkProgram(programId); return programId; } //从shader文件读出字符串 private String readShaderFromResource(int shaderId) { InputStream is = mContext.getResources().openRawResource(shaderId); BufferedReader br = new BufferedReader(new InputStreamReader(is)); String line; StringBuilder sb = new StringBuilder(); try { while ((line = br.readLine()) != null) { sb.append(line); sb.append("n"); } br.close(); } catch (Exception e) { e.printStackTrace(); } return sb.toString(); } //加载纹理贴图 public int loadTexture(int resourceId) { BitmapFactory.Options options = new BitmapFactory.Options(); options.inScaled = false; mBitmap = BitmapFactory.decodeResource(mContext.getResources(), resourceId, options); final int[] textureIds = new int[1]; // 生成纹理id GLES30.glGenTextures(1, textureIds, 0); // 绑定纹理到OpenGL GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, textureIds[0]); GLES30.glTexParameteri(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_MIN_FILTER, GLES30.GL_LINEAR_MIPMAP_LINEAR); GLES30.glTexParameteri(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_MAG_FILTER, GLES30.GL_LINEAR); // 加载bitmap到纹理中 GLUtils.texImage2D(GLES30.GL_TEXTURE_2D, 0, mBitmap, 0); // 生成MIP贴图 GLES30.glGenerateMipmap(GLES30.GL_TEXTURE_2D); // 取消绑定纹理 GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, 0); return textureIds[0]; } }
vertex_shader.glsl
attribute vec4 aPosition; attribute vec2 aTextureCoord; varying vec2 vTexCoord; void main() { gl_Position = aPosition; vTexCoord = aTextureCoord; }
fragment_shader.glsl
precision mediump float; uniform sampler2D uTextureUnit; varying vec2 vTexCoord; uniform float u_time; void main() { vec3 color = texture2D(uTextureUnit, vTexCoord).rgb; color.x += sin(u_time * 1.3 + 0.4) * 0.2; color.y += cos(u_time * 1.7 + 7.1) * 0.2; color.z += (sin(u_time) + cos(u_time)) * 0.2; gl_FragColor = vec4(color, 1.0); }
运行效果如下。

声明:本文转自【Android】基于SurfaceControlViewHost实现跨进程渲染。