android ListView性能优化之路 -- 初级
这是一个典型的ListView,当然,不是那种demo级的简单布局。
优化初级:系统机制级优化
界面缓存机制:不管是ios,还是android,都要考虑到巨型数据的情况,比如ListView的Item过万的情况,然后不管一个itemview的布局有多简单,这个界面的内存将巨大无比,即使内存能到较快速的释放,当列表快速滑动的时候,也将巨卡无比,怎么样更少的使用内存,更快的界面绘制,这个是系统级的事情,当然这是google要考虑的:界面缓存。
/** 系统请求ItemView**/ @Override public View getView(int position, View convertView, ViewGroup parent) { /** * 如果系统有缓存,则使用,否则才创建 * 这个缓存是你用过的,不在使用中的ItemView * 例如正在显示第3到9个Item,可能第8个就是第1个Item,第9个复用第2的Item,即将出去的第3被即将进来的第10复用 **/ if (convertView == null) { ListViewItemFor2Lines listViewItemFor2Text = new ListViewItemFor2Lines(); convertView = listViewItemFor2Text; } return convertView; }
这个缓存是不彻底的,当你使用了上一个缓存的界面时候,你怎么去使用它子view? 于是有一种官方推荐的做法:ViewHolder,子view持有(缓存)
@Override public View getView(int position, View convertView, ViewGroup parent) { ViewHolder holder = null; if (convertView == null) { ListViewItemFor2Lines listViewItemFor2Text = new ListViewItemFor2Lines(); holder = new ViewHolder(); holder.view1 = (View)listViewItemFor2Text.findViewById(R.id.view1); holder.view2 = (View)listViewItemFor2Text.findViewById(R.id.view2); holder.view3 = (View)listViewItemFor2Text.findViewById(R.id.view3); //... listViewItemFor2Text.setTag(holder); convertView = listViewItemFor2Text; } holder = (ViewHolder )convertView.getTag(); //holder.view1.set.... //holder.view2.set.... //holder.view2.set.... //... return convertView; } public class ViewHolder { public int position; public View view1; public View view2; public View view3; //... }
到这里,就基本是一个合格的使用者了,但是这够了吗?
认真看第1和第2个Item,其实他们在Layout上是不一样的,复用性不是很强,因为需要重新Layout,我们追求的最极致是什么,就是只要填数据,其他什么都不要做。
系统还准备了一套模板缓存机制。即,可以有多个模板,你要什么模板就直接使用相应的模板。
/** * 各种ItemView的模板总数 */ @Override public int getViewTypeCount() { return ITEMTYPE_COUNT; } /** * 当前ItemView的模板类型 */ @Override public int getItemViewType(int position) { return ITEMTYPE_TYPE; }
当要显示一个ItemView的时候,系统会询问,这个Item是什么模板,拿到类型以后在缓存里面找相应的模板,找到了就返回复用,找不到就返回空,找不到的时候你所创建的新模板将标志为系统拿到的模板类型,等待下次返回复用。这时候你要做的就是要在getViewTypeCount清算模板数量,在getItemViewType返回相应的模板类型。
到这里,初级之路已走完,也不容易,走到这里,基本实用了。