Android并发编程高级面试题汇总最全最细面试题讲解持续更新中👊👊
👀你想要的面试题这里都有👀
👇👇👇
ViewHolder为什么要被声明成静态内部类
这道题想考察什么?
考察同学对静态内部类和非静态内部类的主要区别
考生应该如何回答
这个是考静态内部类和非静态内部类的主要区别之一。非静态内部类会隐式持有外部类的引用,就像大家经常将自定义的adapter在Activity类里,然后在adapter类里面是可以随意调用外部activity的方法的。
当你将内部类定义为static时,你就调用不了外部类的实例方法了,因为这时候静态内部类是不持有外部类的引用的。
可能你会说ViewHolder都很简单,不定义为static也没事吧。确实如此,但是如果你将它定义为static的,说明你懂这些含义。万一有一天你在这个ViewHolder加入一些复杂逻辑,做了一些耗时工作,那么如果ViewHolder是非静态内部类的话,就很容易出现内存泄露。
如果是静态的话,你就不能直接引用外部类,迫使你关注如何避免相互引用。 所以将 ViewHolder内部类 定义为静态的,是一种良好的编程习惯。
另一个方面,将viewHolder 定义为静态内部类,那么这个viewHolder 可以不仅仅在当前类可以用,在其他类里面也可以直接复用这个ViewHolder。
9.32 ListView卡顿的原因以及优化策略
这道题想考察什么?
- 是否了解ListView卡顿的原因以及优化策略与真实场景使用,是否熟悉ListView卡顿的原因以及优化策略在工作中的表现是什么?
考察的知识点
- ListView卡顿的原因以及优化策略的概念在项目中使用与基本知识
考生应该如何回答
导致ListView卡顿的原因有很多,主要包括:Item没有复用、层级过深、数据绑定逻辑过多、滑动时不必要的图片刷新以及频繁的notifyDataSetChanged。
Item没有复用
ListView的Item没有复用是导致卡顿的常见原因。在滑动的过程中,有些Item离开屏幕,有些Item需要进入屏幕。离开屏幕的Item一般会加入到缓存容器中,而不是让item直接被GC的回收。如果有缓存,那么滑动进入屏幕的Item会优先从缓存容器中读取。读取到的缓存会通过给convertView赋值来更新UI。如果没有课复用的item,那么之后每次都会重新创建这些Item,也就是通过LayoutInflater进行Item的创建,LayoutInflater创建Item是采用反射去解析xml因此是比较耗费时间的,这就会带来性能损耗。
布局的层级过深
布局的层级过深是非常容易引起卡顿,原因是ViewGroup会对子View进行多次测量。假设有一个这样的场景:父布局的布局属性是wrap_content、子布局是match_parent,此时的布局过程是:
- 父布局先以0为强制宽度测量子View、然后继续测量剩下的其他子View
- 再用其他子View里最宽的宽度,二次测量这个match_parent的子 View,最终得出它的尺寸,并把这个宽度作为自己最终的宽度。
即 这个过程就对单个子View进行了二次测量。
「而布局嵌套对性能影响则是指数形式的」,即:父布局会对每个子view做两次测量,子view也会对下面的子view进行两次测量,即相当于是 O(2ⁿ)测量。
总的来说,层级过深会导致多次测量,不必要的测量造成了多余的性能消耗,最终有可能会引起页面的卡顿。
数据绑定逻辑过多
数据绑定逻辑过多也容易导致卡顿。在适配器中,我们通过onCreateViewHolder创建Item,创建之后的Item要通过onBindViewHolder进行数据绑定。过程大致如下:先通过position找到数据源中对应的数据,然后再将数据设置到控件的属性中。简单的设置以及一些简单的计算是不会消耗很多的时间的,如果是包含大量的控件属性设置、数据遍历、转化的话时间就会成倍的增长,最终可能就会导致ListView的卡顿。
滑动时不必要的图片刷新
图片的刷新也有可能导致卡顿。如果Item中包含图片并且我们以非常快的速度滑动列表,那么代表着有Item快速离开屏幕,也有Item快速的进入屏幕。快速进入屏幕的Item必须以极短的时间完成数据绑定和图片加载刷新,但图片的加载是需要耗费较大的性能和时间的,频繁的图片加载会延缓Item的数据绑定过程,容易造成卡顿。
频繁的notifyDataSetChanged
频繁的notifyDataSetChanged也是导致ListView卡顿的一大原因。notifyDataSetChanged是刷新ListView的所有Item的界面上展示的数据,所有的Item都刷新数据肯定是十分消耗性能的,如果是频繁的notifyDataSetChanged,那带来的性能消耗肯定更加严重,最终非常有可能导致到卡顿。
解决办法
Item没有复用,这个问题的解决就是加上复用代码,让item的界面和展示的数据可以得以复用,减少之后创建新的item和绑定数据的次数。
@Override
public View getView(int position, View convertView, ViewGroup parent) {
final ViewHolder holder;
ListViewItem itemData = items.get(position);
if(convertView == null){
convertView = View.inflate(context, R.layout.list_item_layout, null);
holder = new ViewHolder();
holder.userImg = (ImageView) convertView.findViewById(R.id.user_header_img);
holder.userName = (TextView) convertView.findViewById(R.id.user_name);
holder.userComment = (TextView) convertView.findViewById(R.id.user_coomment);
convertView.setTag(holder);
}else{
holder = (ViewHolder) convertView.getTag();
}
holder.userImg.setImageResource(itemData.getUserImg());
holder.userName.setText(itemData.getUserName());
holder.userComment.setText(itemData.getUserComment());
return convertView;
}
static class ViewHolder{
ImageView userImg;
TextView userName;
TextView userComment;
}
如上面代码所示,可以先对convertView进行判断,如果为空再通过LayoutInflater创建新的Item,如果不为空则可以复用。然后通过ViewHolder进一步优化,不用ViewHolder的情况下每次设置Item的值都会需要通过convertView.findViewById寻找相关的控件,不方便且耗时,如果在创建Item时将各类控件引用设置到ViewHolder中,以后就可以直接从ViewHolder找控件,是十分节约性能的。
布局的层级过深的解决方式是减少层级,尽量使用约束布局ConstraintLayout。约束布局ConstraintLayout是Google 参考了ios的约束布局创建的,他的功能相当于 RelativeLayout + LinearLayout,而性能相对于他们提升了40%左右,所以通过使用ConstraintLayout可以达到优化性能的目的。
数据绑定逻辑过多的话,首先是区分出与界面有关的逻辑计算和与界面无关的逻辑计算,与界面有关的逻辑计算只能通过优化算法逻辑、数据结构处理,与界面无关的逻辑计算不影响界面的显示可以开线程用于计算。
滑动时不必要的图片刷新这个解决办法就十分明确,如果快速滑动带来了很多不必要的刷新,那么可以在快速滑动的时候设置为不刷新图片,这样可以减少非常多不必要的性能消耗。
频繁的notifyDataSetChanged是容易导致卡顿的,这种情况可以优化代码逻辑,减少频繁的notifyDataSetChanged。
由于面试题内容比较多,篇幅有限,资料已经被整理成了PDF文档,有需要2023年Android中高级最全面试真题答案 完整文档的可扫描下方卡片免费获取~

PS:(文末还有使用ChatGPT机器人小福利哦!!大家不要错过)
目录

第一章 Java方面
- Java基础部分
- Java集合
- Java多线程
- Java虚拟机

本文详细解读了Android面试中关于ViewHolder静态内部类的设计选择,以及ListView卡顿的原因和优化策略,包括复用、层级、数据绑定、图片刷新和notifyDataSetChanged的优化技巧。
1576

被折叠的 条评论
为什么被折叠?



