1.背景
这是一个视频通话的项目,就类似于微信视频通话,但是和微信等其它一些视频通话 app 的逻辑有一些不一样的逻辑,例如微信拨打别人时会直接进入视频页面,根据设备的性能(如果性能不好,可能会慢吞吞的打开摄像头预览)来打开己方画面,这时就算慢一点打开预览,用户也不会关心的,为什么呢?因为还没接通嘛,谁会关心自己的画面有没有出来呢,然后等到对方接听后,再直接显示对方画面,这样就无缝衔接上了,很正常的流程。
但是我们的项目里流程有一些不一样,在你呼叫别人时,是先打开一个呼叫页面(如下图),等待对方接听后才会进入视频页面,然后这里有个问题,一进入视频页面就要立即初始化视频通话组件,加载 UI,初始化摄像头,打开摄像头预览,这一系列的工作全挤到一起了,设备性能不好的情况下,能明显感觉到卡顿,很不巧,我们做的是机顶盒上的项目,1+4G 的设备,什么是1+4G? 699 块的 Redmi 7是 3+32G 的,清楚了吧;这还不是关键的,中间项目里的视频组件换了一次,新的视频组件不支持单呼,只能群聊,真是令人窒息的操作呀!这意味着你想呼叫别人必须先创建个房间,这还没完,创建房间时必须把用来显示自己预览画面和对方视频画面的 surfaceView 给传进去,所以前面说的呼叫页面只能放到视频页面弹出,正常单呼应该在视频页面之前弹出,接通之后才进入视频页面的,还好当时设计时是个 dialog,然后这时问题就出来了,下面是视频页面具体步骤:
1.视频 Activity打开,开始加载里面有两个大SurfaceView的 UI 布局,卡顿1;
2.创建视频通话组件,创建房间,传入surfaceView,同时弹出呼叫页面;
3.open camera,打开预览,卡顿2;
呼叫页面上有一个点点和水波纹动画,只要主线程有一点耗时就能看出来动画卡顿;
2.分析卡顿
用 as 自带工具查看耗时,首先看到了第一个耗时的地方,页面在加载布局时,surfaceView 加载及相关操作就特别耗时
这个还不是很麻烦,考虑用 ViewStub 优化一下加载耗时:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/activity_ring"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/mblack">
<!--camera-->
<ViewStub
android:id="@+id/viewStubCamera"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout="@layout/layout_camera_surface"
/>
<ViewStub
android:id="@+id/viewStubRender"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout="@layout/layout_render_surface"
/>
...
</RelativeLayout>
两个 layout 文件里都是 surfaceView 和一些相关的 View,然后在页面上等到需要时才去加载
private List<SurfaceView> buildSurfaceViewList() {
if (null == viewStubCamera) {
viewStubCamera = (ViewStub) findViewById(R.id.viewStubCamera);
viewStubCamera.inflate();
camera_holder = (RelativeLayout) this.findViewById(R.id.camera_holder);
mCameraView = (SurfaceView) this.findViewById(R.id.camera_surface);
}
if (null == viewStubRender) {
viewStubRender = (ViewStub) findViewById(R.id.viewStubRender);
viewStubRender.inflate();
render_holder = (RelativeLayout) this.findViewById(R.id.render_holder);
mRenderView = (SurfaceView) this.findViewById(R.id.render_surface);
}
mSurfaceViewList.add(mCameraView);
mSurfaceViewList.add(mRenderView);
return mSurfaceViewList;
}
这是官方推荐的一种布局优化的方式,测试发现对当前遇到的这种情况效果很不错。
但是这时打开视频页面时依然有个任务会使页面卡顿了一下,接着分析发现 camera 在打开预览时耗时将近一秒,看下图:
这是因为视频通话组件是在呼叫时就打开了摄像头并开启了预览,实际上在我们这个项目流程里,对方未接听前,会全屏显示呼叫页面,就算打开摄像头预览用户也看不见的,所以根本就没必要打开预览,然后和视频通话组件相关开发人员沟通后决定把打开预览放到用户接听之后,修改完成测试,明显不再卡顿了。