移动测试基础 Android 6.0 针对 onVisibilityChanged 与 findViewById 执行顺序有改变的坑

Heyniu · 2016年07月19日 · 最后由 Freenovo 回复于 2016年09月19日 · 3687 次阅读
本帖已被设为精华帖!

上期回顾

现象

Android 6.0 以下(正常显示)

Normal

Android 6.0(含)以上(有 Bug)

Bug

问题排查

  • 手机
  • 版本
  • 代码
  • 混淆
  • 调试

时间线

  1. 起初在小米 4(Android 6.0)发现应用 A 正式预览版在某个页面暂无聊天不显示图片
  2. 对比三星 note4(Android 5.1)正常显示图片,怀疑是混淆问题
  3. 应用 A 正式预览版解除混淆,在小米 4 上还是不显示图片
  4. 在小米 4 上安装应用 A 的测试版本,以防代码变动导致的不显示图片,结果表明测试版本在小米 4 上还是不显示图片
  5. 在另外台 Android 6.0 手机上安装应用 A 正式预览版,发现图片也是不 显示,推断问题发生在 Android 6.0 上
  6. 进入代码调试阶段,加入断点和日志打印

为什么问题在测试版未发现,而在正式预览版才暴露?

  • 测试版本期间主要使用 Android 4.4 、Android 5.X 等市场占有率高的版本,以为 Android 6.X 辅助测试
  • 此问题是在无数据的情况下才发生,可能以 Android 6.X 版本测试时,此页面是有数据的情况
  • 相同代码下的 2 个页面,只有 A 页面才发生此 Bug
  • 综上所述

测试关注点

  • 以后项目测试多加关注 Android 6.X
  • 结合以往经验,需重点关注小米机型

问题推进

相关代码

/**
     * loadView 隐藏时停止播放动画,并设置张小图回收点资源
     * @param changedView
     * @param visibility
     */
    @Override
    protected void onVisibilityChanged(View changedView, int visibility) {
        // TODO Auto-generated method stub
        super.onVisibilityChanged(changedView, visibility);
        if (visibility == View.GONE) {
            Log.d("loadView", "onVisibilityChanged GONE");
            stopAnim();
            if(imgv_pic != null){
                imgv_pic.setImageResource(R.drawable.ic_user_page_indicator2);
                Log.d("loadView", "onVisibilityChanged GONE >> setImage");
            }
        }
    }

布局 xml 代码

<com.a.widget.LoadingView
    android:id="@+id/view_no_msg_data"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_centerInParent="true"
    android:visibility="gone">
</com.a.widget.LoadingView>

Android 6.0 以下执行顺序(含问题分析)>> 先 xml 再 java,针对android:visibility属性

  1. 先执行 onVisibilityChanged 方法,因为此时 View 未初始化所以imgv_pic = null,不会执行到设置 Image 的语句imgv_pic.setImageResource(R.drawable.ic_user_page_indicator2);
  2. 再初始化 View,再使用的时候设置为 VISIBLE,所以图片正常显示
D/loadView: onVisibilityChanged GONE
D/loadView: super init >> inflater.inflate:loadView
D/loadView: init view >> findViewById
D/loadView: init view >> setMode 
D/loadView: Visibility >> VISIBLE

Android 6.0(含)以上执行顺序(含问题分析)>> 先 java 再 xml,针对android:visibility属性

  1. 先初始化 View,并调用setMode方法设置 imgv_pic 的资源图片,此时 imgv_pic 不为空
  2. 再执行 onVisibilityChanged 方法,因为此时 imgv_pic 不为空,所以进入了 setImage 方法设置了一张小图(参见前面代码),等需要该 LoadingView 显示的时候,显示出来就看到只有暂无聊天这几个字,未发现有 ImageView(此时的 ImageView 是张小图,小到肉眼发现不了),所以此时有 Bug
D/loadView: super init >> inflater.inflate:loadView
D/loadView: init view >> findViewById
D/loadView: init view >> setMode 
D/loadView: onVisibilityChanged GONE
D/loadView: onVisibilityChanged GONE >> setImage
D/loadView: Visibility >> VISIBLE

额外收获

问题代码

if(imgv_pic != null){
    getRunningAppProcessInfo();
    imgv_pic.setImageResource(R.drawable.ic_user_page_indicator2);
    Log.d("loadView", "onVisibilityChanged GONE >> setImage");
    getRunningAppProcessInfo();
}

日志打印

I/memory: processName=com.a.b.c,pid=19116,uid=10604,memorySize=31992kb
D/loadView: onVisibilityChanged GONE >> setImage
I/memory: processName=com.a.b.c,pid=19116,uid=10604,memorySize=32056kb
  • 事实证明 ImageView 在隐藏时设置小图回收点资源的做法是徒劳无功的
  • 去掉设置小图回收资源的方法

解决方案

  • 去掉设置小图回收资源的方法

验证方案

在 Android 6.0(含)以上、Android6.0 以下版本中验证修改后的代码,均正常显示。

Tips

  • 在自定义 View 中重写了 onVisibilityChanged 方法并且 ImageView 发生改变时,在调用view.setVisibility(View.VISIBLE)的方法前,需要再次设置一次图片
如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
共收到 14 条回复 时间 点赞

写的真细,赞一个

Heyniu #14 · 2016年07月19日 Author

#1 楼 @darker50 谢谢支持😂

赞一个!不错不错!!!

Heyniu #12 · 2016年07月19日 Author

#3 楼 @qg__gq 谢谢支持😂

给 32 个赞

陈恒捷 将本帖设为了精华贴 07月20日 11:05

加精理由:问题描述及解决过程、解决方案非常详细,排版也很漂亮。

直接 imgv_pic 设置成 GONE 或者 VISIABLE 感觉就可以了,为什么要设置一个小图?楼主能给解释一下么?

Heyniu #10 · 2016年07月21日 Author

#9 楼 @yangchengtest 这个不知道开发怎么搞的,听他们说这个是动态图,后来问题暴露后发现设置小图的方法是无效的

@heyniu 好的,楼主加油!~赞一个!~

Android 6.0 的执行顺序是否存在问题?

#13 楼 @liuxiaoyao0602 只是 onVisibilityChanged 与 findViewById 执行顺序有改变

厉害 赞一个

需要 登录 后方可回复, 如果你还没有账号请点击这里 注册