【Android】基于SurfaceControlViewHost实现跨进程渲染

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实现跨进程渲染

【Android】基于SurfaceControlViewHost实现跨进程渲染

2 AIDL 配置

​ Android 跨进程通信可以使用 AIDLmessenger,它们本质都是 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;         }     }; } 

​ 运行效果如下。

【Android】基于SurfaceControlViewHost实现跨进程渲染

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实现跨进程渲染

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

发表评论

评论已关闭。

相关文章