ListView
来源:互联网 发布:阿里 知乎 编辑:程序博客网 时间:2024/05/29 10:55
相信大家在开发过程中,肯定用过ListView,那么关于ListView的面试题有哪些呢,我们一起来看看。
一、什么是ListView
当面试官问你什么是ListView,你的脑海中是不是只有图像没有语言,所以给大家讲一下什么是ListView。
ListView就是可以把数据集合以滚动的方式展示到屏幕上的一个view。
两个关键点:一个数据集合,一个滚动的方式。
二、 ListView适配器模式
提到ListView,大家肯定会想到Adapter,Adapter叫做适配器,它会给每一条数据源制作一个View,然后交由ListView来展示,所以适配器就像是数据源和ListView之间的桥梁一样,把两者联系在一起。
三、ListView中的RecycleBin机制
那大家有没有想过为什么ListView就可以实现滑动的效果呢?先给大家放一张图。
上面这张图就很好的解释了为什么我们的ListView可以实现滑动的效果。原来我们的ListView中的每一个元素就是一个Item,当这个Item滑出屏幕的时候,它会被添加到一个叫RecycleBin的东西里面,而新进入屏幕的元素则会从RecycleBin里面取出一个Item然后装载数据显示到ListView上,这样就实现了一个循环,只要有数据源就可以不停的往RecycleBin中加入Item,取出Item。
那说了这么久的RecycleBin,它到底是个啥嘞?
点开它的源码我们可以看到,它当中有很多的数组变量,我们当然不会关注那么多,大家根据上面的图想一想,我们是不是只要知道三个变量就行了,第一个就是当前ListView中能看到的所有元素,第二个就是所有已经被加入到RecycleBin中的元素,第三个就是当前正要准备加入到RecycleBin中的元素。
private View[] mActiveViews = new View[0]; //存储的是活动的Views,即显示在屏幕上的Views,可以被直接复用private ArrayList<View>[] mScrapViews;//二维数组,表示所有被废弃类型的View的集合private ArrayList<View> mCurrentScrap;//表示当前被废弃的View的集合
当然了,ListView中的数据有很多种类型,比如纯文字的,文字加一张图的,文字加两张图的等等,每一种数据源只能复用相同的Item,否则就会出现排版错乱。所以RecycleBin通过下面这个方法为我们每一种数据类型建立了一个RecycleBin机制,让后面的元素选择。也就是说RecycleBin只有一个,但是它里面有很多的集合,每一个集合就是一个数据类型。
//为ListView中的每一个类型的数据项建立一个recycleBin机制//默认为1,只有一种数据类型public void setViewTypeCount(int viewTypeCount) { if (viewTypeCount < 1) { throw new IllegalArgumentException("Can't have a viewTypeCount < 1");}//noinspection unchecked ArrayList<View>[] scrapViews = new ArrayList[viewTypeCount]; for (int i = 0; i < viewTypeCount; i++) { scrapViews[i] = new ArrayList<View>(); //创建viewTypeCount个集合} mViewTypeCount = viewTypeCount; mCurrentScrap = scrapViews[0]; mScrapViews = scrapViews;}
滑出屏幕的Item通过下面这个方法加入到RecycleBin中:
//把当前要废弃的View添加到ScrapView数组当中void addScrapView(View scrap, int position) {final AbsListView.LayoutParams lp = (AbsListView.LayoutParams) scrap.getLayoutParams();if (lp == null) {// Can't recycle, but we don't know anything about the view.// Ignore it completely.return;}lp.scrappedFromPosition = position;// Remove but don't scrap header or footer views, or views that// should otherwise not be recycled.final int viewType = lp.viewType;if (!shouldRecycleViewType(viewType)) {// Can't recycle. If it's not a header or footer, which have// special handling and should be ignored, then skip the scrap// heap and we'll fully detach the view later.if (viewType != ITEM_VIEW_TYPE_HEADER_OR_FOOTER) {getSkippedScrap().add(scrap);}return;}
新滑入的Item想要显示就要从RecycleBin中去取。
/*** @param childCount 要存储的View的数量* @param firstActivePosition ListView中第一个可见元素的position值*/void fillActiveViews(int childCount, int firstActivePosition) { if (mActiveViews.length < childCount) { mActiveViews = new View[childCount];} mFirstActivePosition = firstActivePosition; //noinspection MismatchedReadAndWriteOfArray final View[] activeViews = mActiveViews; for (int i = 0; i < childCount; i++) { View child = getChildAt(i); AbsListView.LayoutParams lp = (AbsListView.LayoutParams) child.getLayoutParams(); // Don't put header or footer views into the scrap heap if (lp != null && lp.viewType != ITEM_VIEW_TYPE_HEADER_OR_FOOTER) { // Note: We do place AdapterView.ITEM_VIEW_TYPE_IGNORE in active views. // However, we will NOT place them into scrap views. activeViews[i] = child; // Remember the position so that setupChild() doesn't reset state. lp.scrappedFromPosition = firstActivePosition + i; } }}
/** 和fillActiveViews配套使用,用于获取屏幕上显示的View* @param position The position to look up in mActiveViews* @return The view if it is found, null otherwise*/View getActiveView(int position) { int index = position - mFirstActivePosition; final View[] activeViews = mActiveViews; if (index >=0 && index < activeViews.length) { final View match = activeViews[index]; //将可见元素的position值作为可见view集合的角标使用 activeViews[index] = null; //设为null,所以屏幕上的View不能被重复利用 return match; } return null;}
通过这两个方法,就可以让新滑入的元素显示到屏幕上。
好了,关于ListView的源码就分析到这里了,主要就是三个变量,一个是当前屏幕上显示的所有元素的集合,一个就是所以已经被废弃的元素的集合,还要一个就是当前正要废弃的被废弃的元素。然后就是把要废弃的元素加入到RecycleBin中,新滑入的元素从RecycleBin中取出并显示到ListView中。但是有一点要注意就是,只有被加入到RecycleBin中的Item才可以复用,正在屏幕上显示的Item是不可以复用的。
四、ListView的优化
1、Item显示优化
我们都知道ListView每一次要显示一个新元素的时候都要销毁旧元素,再创建新元素,频繁的销毁创建会导致ListView卡顿,也会让整个界面显得不流畅,所以针对ListView,我们可以进行一些优化,来让它不那么频繁的销毁创建,而是复用之前的Item。
使用convertView和ViewHolder来配合。
每当有view移出界面的时候,它就会变成convertView,所以,在调用getView()方法时,我们先判断一下convertView是否为空,如果为空的话,我们就新创建一个布局和viewHolder,并使用viewHolder来绑定convertView中的控件,并且把viewHolder保存在convertView中。如果convertView不为空,那么就直接取出其中保存的viewHolder,再进行其他的操作。viewHolder是一个内部类,它里面保存了ListView中所有控件的信息,减少了findViewById的次数。
这样我们就完成了item显示的优化。我们知道ListView中很多时候都要显示图片,所以针对图片,我们也可以进行一些优化。
2、图片显示优化
可以用三级缓存来展示图片;在geiView方法中做耗时操作会导致界面的卡顿,所以我们可以为ListView设置一个滑动监听,界面滑动的时候我们不去加载图片,界面停止的时候我们才去加载图片。
3、硬件加速
开启硬件加速,也可以提高ListView展示的效率。
另外还有一些其他的方法,比如设置半透明元素等等,这里就不多说了,主要的方法就是上面第一点和第二点。
总结
好了,总结一下吧,ListView就是一个可以将数据集合以滚动的方式展示到屏幕上的view。每一个Item都是通过Adapter来创建View的,Adapter就像是数据源和ListView之间的桥梁。它实现滚动的方式,是因为它的内部有一个RecycleBin,可以存放滑出屏幕的元素的Item,需要显示的元素从RecycleBin中取出Item并加载自己的数据来让ListView显示。针对ListView我们还做了很多的优化来提高性能,比如复用convertView和内部类viewHolder,比如图片的三级缓存,比如设置滑动监听等等。
好了,继续学习喽~~~
- listview
- listview
- listview
- ListView
- ListView
- listview
- listview
- listView
- ListView
- ListView
- ListView
- listview
- LIstView
- ListView
- listview
- ListView
- ListView
- ListView
- static关键字修饰变量的加载和初始化过程(Java)
- 正则表达式 零宽断言(正向和负向)
- [HNOI]2003 消防局的建立
- hive 中的二级分区表和动态分区表
- leetcode#2-Add Two Numbers-java
- ListView
- 正则表达式 贪婪与懒惰
- Android面试——AsyncTask
- Android四大组件之BroadcastReceiver
- 计分器
- 游戏手柄(JoyStick)编程学习笔记(2)
- 数字货币交易平台对接开发钱包之间的RPC解决方法
- 隐藏与覆盖
- Spring定时器小结