前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >踩坑记-databinding

踩坑记-databinding

作者头像
韦东锏
发布2021-11-11 14:47:12
5760
发布2021-11-11 14:47:12
举报
文章被收录于专栏:Android码农Android码农

问题

每次进入详情页,标题栏都会闪一下,特别是图标部分,很明显,可以看下面的gif

如果不明显,可以看下面两张对比图片

异常态

正常态

可以看到,在打开详情页的动画过程中,会闪一下异常的UI

问题分析

首先看下现有的代码

代码语言:javascript
复制
<TextView                                                                                    
    style="@style/detail_tag_style"                                                          
    android:layout_marginRight="6dp"                                                         
    android:text="@string/platform_offers"                                                   
    android:visibility="@{(item.isCashBack == true)?View.VISIBLE:View.GONE}" /> 
<ImageView                                                                                     
    android:id="@+id/ivAllowInvoice"                                                           
    android:background="@drawable/icon_invoice"                                                
    android:layout_width="16dp"                                                                
    android:layout_height="16dp"                                                               
    android:layout_marginRight="6dp"                                                           
    android:visibility="@{(item.allowInvoice == true)?View.VISIBLE:View.GONE}" /> 

可以看到,布局是使用databinding来实现的,用item的值来判断可见性,自行验证了下,item的值没有问题,设置item是在onbindviewholder设置的,我们看下代码

代码语言:javascript
复制
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {   
    val detailItem = detail.spuDetailResult                                                          
    if (holder is ImageItemHolder) {                                                                 
        //忽略                                                                                
    } else if (holder is DetailTopHolder) {                                                          
        holder.topBinding.item = detailItem    //绑定数据的地方                                                      
        //其他代码忽略    
    }                                                                                            
}                                                                                                    

topBinding的对象是ItemDetailTopItemBinding,设置item的方法,是AS自动生成的,叫做ItemDetailTopItemBindingImpl,具体实现在这个类里面

代码语言:javascript
复制
public void setItem(@Nullable com.ygp.mro.data.GoodsDetail Item) { 
    this.mItem = Item;                                             
    synchronized(this) {                                           
        mDirtyFlags |= 0x1L;                                       
    }                                                              
    notifyPropertyChanged(BR.item);                                
    super.requestRebind(); //这里触发刷新                                        
}                                                                  

继续往下看

代码语言:javascript
复制
protected void requestRebind() {
//其他代码忽略
    if (USE_CHOREOGRAPHER) {                                            
            mChoreographer.postFrameCallback(mFrameCallback);               
        } else {                                                            
            mUIThreadHandler.post(mRebindRunnable);                         
        }                                                                  
}                                                                           

最终实现的是mChoreographer.postFrameCallback方法,可以知道,其实是异步实现的,所以问题的是

databinding设置data是异步生效(下一次绘制),不是直接生效

问题解决

问题的解决,有两个方案

方案1:这里不用databinding,直接在onbindViewHolder代码里面,手动设置

代码语言:javascript
复制
val visilble = if (detailItem.allowInvoice) {                 
    View.VISIBLE                                              
} else {                                                      
    View.GONE                                                 
}                                                             
holder.topBinding.ivAllowInvoice.visibility = visilble        

这样就可以避免闪烁的问题了,不过同时也没有用到databidning特性了,违背了原本的设计思路

方案2:设置default属性

可以在xml里面,设置view默认为不可见

代码语言:javascript
复制
<ImageView                                                                                    
    android:id="@+id/ivAllowInvoice"                                                          
    android:background="@drawable/icon_invoice"                                               
    android:layout_width="16dp"                                                               
    android:layout_height="16dp"                                                              
    android:layout_marginRight="6dp"                                                          
    android:visibility="@{(item.allowInvoice == true)?View.VISIBLE:View.GONE,default=gone}" />

最后的这个default=gone就会设置默认不可见(感谢伟华提供方案),所以也就不会闪一下了,这个default属性在官方的文档里面没有提到,还是在网上搜索到的

内部原理

为什么加了default=gone就不会闪了,抱着这个疑问,分别对比了有设置default=gone跟没有设置,自动生成的ItemDetailTopItemBinding类,有没有差别,最终发现,没有任何差别

接着怀疑,问题应该是处在最终的apk上面,于是把生成的apk的xml打开,发现如下情况

代码语言:javascript
复制
<ImageView                                          
    android:id="@ref/0x7f0a0171"                    
    android:tag="binding_11"                        
    android:background="@ref/0x7f08009d"            
    android:visibility="2"                          
    android:layout_width="dimension(4097)"          
    android:layout_height="dimension(4097)"         
    android:layout_marginRight="dimension(1537)" /> 

自动给view加了visibility="2"的属性,2就是代表View.GONE,原来是在apk打包的时候,给view自动加了不可见的属性

总结

databinding设置data,是异步生效,如果碰到闪烁情况,可以加default属性 其实还有个疑问,虽然是异步生效,但其实是下一帧绘制的时候生效,理论上也是不应该出现闪烁的,这个闪烁,我发现是部分机型上才会出现,也不是所有机型必现的,这个涉及不同rom底层的实现,暂时也还没弄清楚...

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2021-11-04,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Android码农 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 问题
  • 问题分析
  • 问题解决
    • 方案1:这里不用databinding,直接在onbindViewHolder代码里面,手动设置
      • 方案2:设置default属性
      • 内部原理
      • 总结
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档