用SurfaceControlViewHost 跨进程显示view

一. server 端

java 复制代码
public class SurfaceControlService extends Service {
    private final String TAG = "SurfaceControlService";
    private Handler mHandler ;
    private SurfaceControlViewHost mSurfaceControlViewHost;


    private ImageView mImageView;
    public SurfaceControlService() {
    }

    @Override
    public void onCreate() {
        super.onCreate();
        mHandler = new Handler(Looper.getMainLooper());
    }

    @Override
    public IBinder onBind(Intent intent) {
       return  mBinder;
    }
    private IBinder mBinder = new IRemoteRender.Stub() {
        @Override
        public SurfaceControlViewHost.SurfacePackage getSurfacePackage(int displayId, IBinder hostToken, int width, int height) throws RemoteException {
            Log.d(TAG, "getSurfacePackage, displayId=" + displayId + ", hostToken=" + hostToken + ", width=" + width + ", height=" + height);
            final SurfaceControlViewHost.SurfacePackage[] result = new SurfaceControlViewHost.SurfacePackage[1];
            final CountDownLatch latch = new CountDownLatch(1);
            mHandler.post(new Runnable() {
                @RequiresApi(api = Build.VERSION_CODES.R)
                @Override
                public void run() {
                    //创建 SurfaceControlViewHost
                    Context context = getBaseContext();
                    Display display = context.getSystemService(DisplayManager.class).getDisplay(displayId);
                    mSurfaceControlViewHost = new SurfaceControlViewHost(context, display,hostToken);

                    mImageView = new ImageView(context);
                    mImageView.setLayoutParams(new ViewGroup.LayoutParams(width,height));
                    mImageView.setScaleType(ImageView.ScaleType.FIT_XY);
                    mImageView.setImageResource(R.drawable.test);
                    // 确保可以接收触摸事件
                    mImageView.setClickable(true);
                    mImageView.setFocusable(true);
                    mImageView.setFocusableInTouchMode(true);
                    mSurfaceControlViewHost.setView(mImageView,width,height);
                    result[0] = mSurfaceControlViewHost.getSurfacePackage();
                    latch.countDown();//每调用一次就减 1
                }
            });
            try{
                latch.await();//等待子进程完成任务,再执行主进程
            }catch (InterruptedException e){
                e.printStackTrace();
            }
            return result[0];
        }

        @Override
        public boolean onTouch(MotionEvent motionEvent) throws RemoteException {
            final CountDownLatch latch = new CountDownLatch(1);
            Log.d(TAG,"onTouch is called.");
            final boolean[] result = new boolean[1];

            mHandler.post(new Runnable() {
                @Override
                public void run() {
                    MotionEvent newEvent = MotionEvent.obtain(motionEvent);
                    newEvent.recycle();
                    //mImageView.setImageResource(R.drawable.ic_launcher_background);
                    Log.d(TAG,"onTouch is called.");
                    latch.countDown();
                }
            });
            try{
                latch.await();
            }catch (InterruptedException e){
                e.printStackTrace();
            }
            return false;
        }

        @Override
        public void onClick() throws RemoteException {
            final CountDownLatch latch = new CountDownLatch(1);
            Log.d(TAG,"onTouch is called.");
            final boolean[] result = new boolean[1];

            mHandler.post(new Runnable() {
                @Override
                public void run() {

                    mImageView.setImageResource(R.drawable.ic_launcher_background);
                    Log.d(TAG,"onClick is called.");
                    latch.countDown();
                }
            });
            try{
                latch.await();
            }catch (InterruptedException e){
                e.printStackTrace();
            }
        }
    };

    @RequiresApi(api = Build.VERSION_CODES.R)
    @Override
    public void onDestroy() {
        super.onDestroy();
        if(mSurfaceControlViewHost != null) {
            mSurfaceControlViewHost.release();
        }
    }
}

AIDL 文件

arduino 复制代码
interface IRemoteRender {
    //客户端提供surface 、大小
    SurfacePackage getSurfacePackage(int displayId,IBinder hostToken,int width,int height);
    //客户端向服务端传递事件
    boolean onTouch(in MotionEvent motionEvent);
    void onClick();
}

二. 客户端

typescript 复制代码
public class MainActivity extends AppCompatActivity {
    public static final String SERVICE_PKG_NAME = "com.android.surfacecontrolviewhosttest";
    public static final String SERVICE_CLASS_NAME = "com.android.surfacecontrolviewhosttest.SurfaceControlService";

    private ServiceConnection mServiceConnection ;
    private IRemoteRender mRemoteRender;
    private IBinder mBinderToken;
    private SurfaceView mSurfaceView;
    private Context mContext;
    private String TAG = MainActivity.class.getSimpleName();
    private SurfaceControlViewHost.SurfacePackage mSurfacePackage;
    private IBinder.DeathRecipient mDeathRecipient = new IBinder.DeathRecipient() {
        @Override
        public void binderDied() {
            clearBind();
        }
    };
    @RequiresApi(api = Build.VERSION_CODES.R)
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mContext = this;
        EdgeToEdge.enable(this);
        setContentView(R.layout.activity_main);
        connectService(this);
        setUp();
    }
    private void connectService(Context context){
        Intent intent = new Intent();
        intent.setComponent(new ComponentName(SERVICE_PKG_NAME,SERVICE_CLASS_NAME));
        mServiceConnection = new ServiceConnection() {
            @Override
            public void onServiceConnected(ComponentName name, IBinder service) {
                mRemoteRender = IRemoteRender.Stub.asInterface(service);
                Log.d(TAG,"onServiceConnected is called");
            }

            @Override
            public void onServiceDisconnected(ComponentName name) {
                Log.d(TAG,"onServiceDisconnected is called");
                clearBind();
            }
        };
        boolean result = context.bindService(intent,mServiceConnection,Context.BIND_AUTO_CREATE);
        Log.d(TAG,"result = "+result);
    }
    private void unbindService(Context context) {
        if (mServiceConnection != null) {
            context.unbindService(mServiceConnection);
        }
    }
    @RequiresApi(api = Build.VERSION_CODES.R)
    public void onClickDraw(View view){
        mBinderToken = mSurfaceView.getHostToken();
        try {
            mSurfacePackage = mRemoteRender.getSurfacePackage(0,mBinderToken,mSurfaceView.getWidth(),mSurfaceView.getHeight());
            mSurfaceView.setChildSurfacePackage(mSurfacePackage);
        } catch (RemoteException e) {
            throw new RuntimeException(e);
        }
    }
    @RequiresApi(api = Build.VERSION_CODES.R)
    private void setUp(){
        mSurfaceView = findViewById(R.id.surface_view);
        mSurfaceView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Log.d(TAG,"onClick is called");
                try {
                    mRemoteRender.onClick();
                } catch (RemoteException e) {
                    throw new RuntimeException(e);
                }
            }
        });
        mSurfaceView.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {

                try {
                    return mRemoteRender.onTouch(event);
                } catch (RemoteException e) {
                    throw new RuntimeException(e);
                }
            }
        });
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        unbindService(mContext);
    }
    private void clearBind(){
        Log.d(TAG,"clearBind is called");
        if(mRemoteRender != null){
            mRemoteRender.asBinder().unlinkToDeath(mDeathRecipient,0);
            mRemoteRender = null;
        }
    }
}

三. 效果图 点击 draw 按钮就可以显示图片,点击图片,就可以换一个图片 这一切实际显示都是在server端完成, 点击事件也传递给服务端,在服务端完成。

四. 完整代码

github.com/lixiangdeba...

相关推荐
城东米粉儿2 小时前
Android消息机制 笔记
android
诸神黄昏EX2 小时前
Android SystemServer 系列专题【篇五:SystemConfig系统功能配置】
android
城东米粉儿2 小时前
Android IdleHandler 优化笔记
android
城东米粉儿2 小时前
Android Binder 笔记
android
Android系统攻城狮2 小时前
Android tinyalsa深度解析之pcm_get_available_min调用流程与实战(一百一十六)
android·pcm·tinyalsa·音频进阶·音频性能实战
lxysbly2 小时前
nds模拟器安卓版官网
android
hewence12 小时前
协程间数据传递:从Channel到Flow,构建高效的协程通信体系
android·java·开发语言
前端不太难2 小时前
为什么鸿蒙不再适用 Android 分层
android·状态模式·harmonyos
2501_916007472 小时前
ios上架 App 流程,证书生成、从描述文件创建、打包、安装验证到上传
android·ios·小程序·https·uni-app·iphone·webview