登录
首页 > 别克 > 探索淘宝购物车SurfaceView闪黑的解决方案

探索淘宝购物车SurfaceView闪黑的解决方案

发布时间:2025-02-15 16:38:55 发布用户: 15210273549

如何应对产品形态与产品节奏相对确定情况下转变为『在业务需求与产品形态高度不确定性的情况下,如何实现业务交付时间与交付质量的确定性』。我们希望通过混合架构(Native 业务容器 + Weex 2.0)作为未来交易终端架构的重要演进方向,在 Native 容器侧充分发挥原生语言的性能优势、常驻 App 的调控与管控能力、手势识别与交互优势来解决体验问题。本专题《淘宝交易终端架构探索》是我们摸索出的部分实践总结,欢迎大家一起交流进步。

 

第一篇:《Weex购物车长列表横滑操作优化“编年史”》

第二篇:《淘宝页面首帧优化的经验和心得》

第三篇:《淘宝App交易链路终端混合场景体验探索》

第四篇:《淘宝订单列表

Fragment转场动画卡顿解决方案

第五篇:《探索淘宝购物车SurfaceView闪黑的解决方案》(本篇)

 


引言

 

购物车的技术架构一直是DX+Native,在业务快速迭代的今天,可能不满足迭代效率,需要探索一种性能佳+迭代快的方式,由此开始探索购物车Weex化。

在进入主TabWeex购物车(SurfaceView)之后,我们发现切换到其他Tab(如:首页),再回到购物车,两次切换都能看到明显的闪黑。

 

,时长00:09


SurfaceView闪黑的原理是什么?

 

SurfaceView继承自 View 类,但与普通的 View 不同,它内部使用了一个独立的绘图表面(即 Surface),这个 Surface 可以在主 UI 线程之外的线程上进行控制和绘制。这样做的好处是,即使绘制操作很复杂,也不会影响到 UI 线程的响应性和流畅性。

 

View视图位于自绘视图Render Surface下方,通过对自绘视图的Render Surface挖洞来透出下面的View视图。

 

Tab切换页面的原理是FragmentManager的attach和detach,会触发Fragment根布局的add/remove,最终导致SurfaceView从View树上添加/移除,进而影响SurfaceView的可见性。

 

闪黑问题本质上是:SurfaceView的可见性发生变化时,会导致其内部的Surface被销毁/重建。在没有内容呈现的情况下,SurfaceView显示为黑色。

 

什么时候SurfaceView可见性会变化?

SurfaceView被removeView,如:主Tab切换
Activity前后台切换,如:打开详情/回到手机Home
Activity销毁,如:finish页面

DX+Native购物车Tab切换为什么没有闪的问题呢?

DX采用原生View绘制,Fragment页面切换受VSync信号和MessageQueue的同步屏障控制,确保在执行完performTraversals()(即View的测量、布局和绘制三大流程)之后,才进行下一步操作,这样可以保证UI的一致性。


方案

 

由于SurfaceView的特性,可见性变化的时候,就可能导致黑屏。业内有几种解决办法:

页面切换不执行remove SurfaceView,只执行visible/gone
盖View,遮住黑屏
Texture/Image->Surface切换


▐Fragment不销毁


概述
主Tab页面切换,由FragmentManager的attach/detach改为show/hide,避免SurfaceView可见性变化

 

效果
Tab切换不会闪。

 

,时长00:07

 

方案细节

修改Fragment切换方式:从attach/detach改为show/hide

 

show/hide不会触发购物车Fragment的生命周期回调,SurfaceView也不会从view树中移除,因此切换不会闪。

 

回到主Tab的场景,如果采用
FragmentManagerattach/detach,会触发Fragment生命周期回调(onDestroyView),内部会把SurfaceView从view树上移除,从而触发onWindowVisibilityChanged,最终导致Surface被destroy,而调用show/hide并不会触发onWindowVisibilityChanged,所以不会导致Surface销毁。

 

▐截屏


概述
从购物车切换到其他Tab时,保存购物车的截屏,再次从其他Tab进入购物车的时候,先显示截屏View,待SurfaceView开始渲染之后,再隐藏截屏View,显示SurfaceView。

 

效果
Tab切换不会闪,但截屏有API系统版本限制(Android 8.0,API 26)

 

,时长00:07

 

方案细节
核心:SurfaceView从View树中移除,内部会销毁当次Surface,所以要想成功截屏必须在这个销毁动作执行之前。
截屏:在Tab切换Preload阶段/back键触发时截图,期间会卡主主线程(设置超时,如:100ms),在截屏完成之后(显示截屏兜底图),再切换Fragment
购物车切到其他Tab,Nav Preload阶段截图并显示兜底图
// 切换到非购物车Tab回调
private val mTabOtherCallback: ()-> Unit = {
    screenShot()
}


// back键返回首页
override fun onBackPress(): Boolean {
    screenShot()
    return false
}


// 伪代码
private val screenShot() {
    val bitmap = requestBitmap()
    // 添加视图bitmap
    mScreenImageView?.setImageBitmap(bitMap)
    mScreenImageView?.setBackgroundColor(if (isSuccess) Color.TRANSPARENT else Color.WHITE)
    mScreenImageView?.visibility = View.VISIBLE
}

回到购物车,weex视图开始绘制,移除兜底图
override fun onWeexUiDisplayed() {
    if (mScreenImageView?.visibility == View.VISIBLE) {
        mScreenImageView?.visibility = View.GONE
    }
}
3. PixelCopy.request存在版本问题,只能在android 8.0及以上版本生效

 

api限制问题

由于PixelCopy.request截图存在系统版本限制,因此针对低于android8.0版本(如:Y67),做如下处理:

上述方案中购物车切换到其他Tab的时候,由显示截图改为显示白色背景图
显示和隐藏兜底图的时机不变
改动的实质是避免SurfaceView切换带来的闪黑问题,添加了白色背景图,从体感上没有那么的突兀

api限制另一种解决思路

通过Weex提供获取SurfaceView bitMap方式:

图片未采样,内存占用太高
图片应该用的是ARGB,购物车没有alpha透明度,可以直接用RGB,内存占用会更小一些
仍然存在耗时问题
列表滚动的时候,切换tab,需要先停止列表,然后再截图


影响

性能损耗:从购物车切换到其他Tab,会执行PixelCopy.request截图本身是耗时的,会卡主主线程,有一定的耗时
截图对内存有轻微影响,但对Java Heap影响不大
如果购物车列表处于滑动/动画/下拉/上拉等非静止状态,切换到其他Tab,再回到购物车,会导致截的图不是最后一帧,视觉上会导致页面抖动
Android低系统版本体验有损,截图降级为白色背景图


▐Image->Surface转换


概述
从购物车去到其他Tab,先切换成ImageView,同步渲染完,再跳转其他Tab;从其他Tab回到购物车,ImageView先上屏,再切换成SurfaceView。

 

效果
其他Tab进入购物车:iv->sv无白帧,很丝滑,购物车切到其他Tab:sv->iv有较多的白帧(待解决,参考了UC Hummer的方案)

Copyright 2017-2024 微学堂 版权所有  京ICP备18049689号-30