Android 6.0针对onVisibilityChanged与findViewById 执行顺序有改变的坑
本帖已被设为精华帖!,
上期回顾
现象
Android 6.0 以下(正常显示)
Android 6.0 (含)以上(有Bug)
问题排查
- 手机
- 版本
- 代码
- 混淆
- 调试
时间线
- 起初在小米4(Android 6.0)发现应用A正式预览版在某个页面暂无聊天不显示图片
- 对比三星note4 (Android 5.1)正常显示图片,怀疑是混淆问题
- 应用A正式预览版解除混淆,在小米4上还是不显示图片
- 在小米4上安装应用A的测试版本,以防代码变动导致的不显示图片,结果表明测试版本在小米4上还是不显示图片
- 在另外台Android 6.0手机上安装应用A正式预览版,发现图片也是不 显示,推断问题发生在Android 6.0上
- 进入代码调试阶段,加入断点和日志打印
为什么问题在测试版未发现,而在正式预览版才暴露?
- 测试版本期间主要使用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
属性
- 先执行onVisibilityChanged方法,因为此时View未初始化所以
imgv_pic = null
,不会执行到设置Image的语句imgv_pic.setImageResource(R.drawable.ic_user_page_indicator2);
- 再初始化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
属性
- 先初始化View,并调用setMode方法设置imgv_pic的资源图片,此时imgv_pic不为空
- 再执行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)
的方法前,需要再次设置一次图片
* 注:本文来自网络投稿,不代表本站立场,如若侵犯版权,请及时知会删除