Android高级UI面试题汇总(含详细解析二十四)

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

Android并发编程高级面试题汇总最全最细面试题讲解持续更新中👊👊
👀你想要的面试题这里都有👀
👇👇👇

ViewHolder为什么要被声明成静态内部类

这道题想考察什么?

考察同学对静态内部类和非静态内部类的主要区别

考生应该如何回答

这个是考静态内部类和非静态内部类的主要区别之一。非静态内部类会隐式持有外部类的引用,就像大家经常将自定义的adapter在Activity类里,然后在adapter类里面是可以随意调用外部activity的方法的。
当你将内部类定义为static时,你就调用不了外部类的实例方法了,因为这时候静态内部类是不持有外部类的引用的。
可能你会说ViewHolder都很简单,不定义为static也没事吧。确实如此,但是如果你将它定义为static的,说明你懂这些含义。万一有一天你在这个ViewHolder加入一些复杂逻辑,做了一些耗时工作,那么如果ViewHolder是非静态内部类的话,就很容易出现内存泄露。
如果是静态的话,你就不能直接引用外部类,迫使你关注如何避免相互引用。 所以将 ViewHolder内部类 定义为静态的,是一种良好的编程习惯。

另一个方面,将viewHolder 定义为静态内部类,那么这个viewHolder 可以不仅仅在当前类可以用,在其他类里面也可以直接复用这个ViewHolder。


9.32 ListView卡顿的原因以及优化策略

这道题想考察什么?

  1. 是否了解ListView卡顿的原因以及优化策略与真实场景使用,是否熟悉ListView卡顿的原因以及优化策略在工作中的表现是什么?

考察的知识点

  1. 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,此时的布局过程是:

  1. 父布局先以0为强制宽度测量子View、然后继续测量剩下的其他子View
  2. 再用其他子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机器人小福利哦!!大家不要错过)

目录

img

第一章 Java方面

  • Java基础部分
  • Java集合
  • Java多线程
  • Java虚拟机

img

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值