ListView的优化

listview可以说是Android开发中最常见的UI控件了,listview能够以列表的方式显示大量同类的数据,这样问题就产生了,既然是大量数据,就会使用到很多布局,给布局绑定数据,listview将占用大量资源还可能会产生卡顿现象。当系统开始绘制ListView的时候,首先调用getCount()方法。得到它的返回值,即ListView的长度。然后系统调用getView()方法,根据这个长度逐一绘制ListView的每一行。也就是说,如果让getCount()返回1,那么只显示一行。而getItem()getItemId()则在需要处理和取得Adapter中的数据时调用。那么getView如何使用呢?如果有10000行数据,就绘制10000次?这肯定会极大的消耗资源,导致ListView滑动非常的慢,那应该怎么做呢?通过一个例子来讲解如何在使用BaseAdapter的时候优化ListView的显示。例子中将上一节中的ImageView换成Button,并且处理Button的点击事件,其中对ListView的显示做了优化。

(1)减少Item的view的次数,即:减少inflater.inflate(R.layout.list_item_icon_text,  null);

public View getView(int position, View convertView, ViewGroup parent) {
    if (convertView == null) {
        convertView = mInflater.inflate(R.layout.list_item_icon_text,null);
    }
    else{
        //具体操作
    } return convertView;
}

(2)减少item里面的每个控件的findViewById的次数。

在Adapter中使用内部类ViewHolder,具体代码如下: 

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    ViewHolder holder;
    if (convertView == null) {
        holder = new ViewHolder();
        convertView = mInflater.inflate(R.layout.list_item_icon_text,null);
        holder.icon = (ImageView) convertView.findViewById(R.id.icon);
        holder.text = (TextView) convertView.findViewById(R.id.text);
        convertView.setTag(holder);
    }
    holder = (ViewHolder)convertView.getTag();
    holder.icon.setImageResource(R.drawable.icon);
    holder.text.setText(mData[position]);
    return convertView;
}

 class ViewHolder {
    TextView text;
    ImageView icon;
}

  在Adapter的代码中,在getView方法里首先判断convertView是否为空,若为空则加载相应布局,若不为空则直接使用该布局,这能够很有效的使用Android为listview提供的缓存机制:只加载一屏的布局,之后滑动出来的item使用的是之前已经加载的布局的缓存;

  而使用ViewHoulder的目的则是节省了findViewById的时间。如果不使用ViewHolder,每次getView的时候都需要得到一次子布局,而这也是很耗时并且耗资源的;如果使用了ViewHolder作为子布局的缓存,使用View的setTag方法将缓存与每个item绑定,则也可以省去了findViewById的事件;

而将ViewHolder设置为static的目的是指在初始化Adapter时初始化一次这个内部类,否则将会在每次创建Adapter时都要初始化一次,而这是没有必要的。

  上述方法能够解决大部分listview消耗资源以及卡顿的问题,但对于不同的需求的listview来说还会存在其他让listview卡顿的原因,比如listview的item每次加载时都需要获得图片并设置到imageview中,item加载时需要进行大量的计算,item里的TextView需要设置指定字体;这些耗时的操作都会让listview滑动起来很卡,带来不好的体验。 


  (3)getView() 中要做尽量少的事情,不要有耗时的操作。

比如item里面有图片的情况下,滑动的时候不要加载,停下来再加载。这点可以用Picasso加载,自带线程,不会造成卡顿。

@Override
public View getView(int position, View view, ViewGroup parent) {
	ViewHolder holder;
	if (view == null) {
		view = inflater.inflate(R.layout.home_listview_item, null);
		holder = new ViewHolder();
		holder.food_image = (ImageView) view.findViewById(R.id.food_image);
		view.setTag(holder);
	}
	holder = (ViewHolder) view.getTag();
	Cook item = list.get(position);
	Picasso.with(context).load(item.getImg()).placeholder(R.drawable.image_loding).into(holder.food_image);
	return view;
	}

参考:http://blog.csdn.net/jdsjlzx/article/details/45914707

  1. package com.zhengsonglan.listview_loading.adapter;  
  2.   
  3. import android.content.Context;  
  4. import android.view.LayoutInflater;  
  5. import android.view.View;  
  6. import android.view.ViewGroup;  
  7. import android.widget.BaseAdapter;  
  8. import android.widget.ImageView;  
  9. import android.widget.TextView; 
  10. import com.nostra13.universalimageloader.core.ImageLoader;  
  11. import com.zhengsonglan.listview_loading.R;  
  12. import com.zhengsonglan.listview_loading.entity.UserEnity;  
  13.   
  14. import java.util.List;  
  15.   
  16. public class MyAdapter extends BaseAdapter {  
  17.     Context context;  
  18.     LayoutInflater inflater;  
  19.     List<UserEnity> lists;  
  20.   
  21.     private  boolean scrollState=false;  
  22.   
  23.     public void setScrollState(boolean scrollState) {  
  24.         this.scrollState = scrollState;  
  25.     }  
  26.   
  27.     public MyAdapter(Context context, List<UserEnity> lists) {  
  28.         this.context=context;  
  29.         this.inflater=LayoutInflater.from(context);  
  30.         this.lists=lists;  
  31.     }  
  32.   
  33.     @Override  
  34.     public int getCount() {  
  35.         return lists==null?0:lists.size();
  36.     }  
  37.   
  38.     @Override  
  39.     public Object getItem(int position) {  
  40.         return lists.get(position);  
  41.     }  
  42.   
  43.     @Override  
  44.     public long getItemId(int position) {  
  45.         return position;  
  46.     }  
  47.   
  48.     @Override  
  49. public View getView(int position, View convertView, ViewGroup parent) {  
  50.         ViewHolder viewHolder;  
  51.         if (convertView == null) {  
  52.             convertView=inflater.inflate(R.layout.main_item,null,true);  
  53.             viewHolder=new ViewHolder();  
  54.             viewHolder.iv_icon= (ImageView) convertView.findViewById(R.id.icon);  
  55.             viewHolder.tv_name= (TextView) convertView.findViewById(R.id.name);  
  56.             convertView.setTag(viewHolder);  
  57.         } else {  
  58.             viewHolder= (ViewHolder) convertView.getTag();  
  59.         }   
  60.         UserEnity userEnity=lists.get(position);  
  61.         String img_url=userEnity.getIcon();  
  62.         if (!scrollState){  //如果当前不是滑动的状态,我们填充真数据 
  63.             viewHolder.tv_name.setText(userEnity.getName());  
  64.             viewHolder.tv_name.setTag(null);  
  65.             ImageLoader.getInstance().displayImage(img_url,viewHolder.iv_icon);  
  66.             viewHolder.iv_icon.setTag("1");  
  67.         }else{  //如果当前是滑动的状态,我们填充假数据 
  68.             viewHolder.tv_name.setText("加载中");  
  69.             viewHolder.tv_name.setTag(userEnity.getName());  
  70.             viewHolder.iv_icon.setTag(img_url);  
  71.     //设置默认显示图片(最好是本地资源的图片
  72.             viewHolder.iv_icon.setImageResource(R.mipmap.ic_launcher);  
  73.         }  
  74.         return convertView;  
  75.   
  76.     }  
  77.   
  78.     static class ViewHolder{  
  79.         TextView tv_name;  
  80.         ImageView iv_icon;  
  81.     }  
  82. }  
我们在看看Activity中的代码,主要是监听listview的onScrollListener方法
[java]  view plain  copy   在CODE上查看代码片 派生到我的代码片
  1. @Override  
  2.     public void onScrollStateChanged(AbsListView view, int scrollState) {  
  3.         switch (scrollState){  
  4.             case AbsListView.OnScrollListener.SCROLL_STATE_IDLE://停止滚动  
  5.             {  
  6.               //设置为停止滚动  
  7.                 myAdapter.setScrollState(false);  
  8.                 //当前屏幕中listview的子项的个数  
  9.                int count = view.getChildCount();  
  10.                 for (int i = 0; i < count; i++) {  
  11.                     //获取到item的name  
  12.        TextView tv_name = (TextView) view.getChildAt(i).findViewById(R.id.name);  
  13.                     //获取到item的头像  
  14.        ImageView iv_show= (ImageView) view.getChildAt(i).findViewById(R.id.icon);  
  15.                     if (tv_name.getTag() != null) { //非null说明需要加载数据  
  16.                         tv_name.setText(tv_name.getTag().toString());//直接从Tag中取出我们存储的数据name并且赋值  
  17.                         tv_name.setTag(null);//设置为已加载过数据  
  18.                     }  
  19.   
  20.                     if (!iv_show.getTag().equals("1")){//!="1"说明需要加载数据  
  21.                         String image_url=iv_show.getTag().toString();//直接从Tag中取出我们存储的数据image——url  
  22.                         ImageLoader.getInstance().displayImage(image_url, iv_show);//显示图片  
  23.                         iv_show.setTag("1");//设置为已加载过数据  
  24.                     }  
  25.                 }  
  26.                 break;  
  27.             }  
  28.             case AbsListView.OnScrollListener.SCROLL_STATE_FLING://滚动做出了抛的动作  
  29.             {  
  30.                 //设置为正在滚动  
  31.                 myAdapter.setScrollState(true);  
  32.                 break;  
  33.             }  
  34.   
  35.             case AbsListView.OnScrollListener.SCROLL_STATE_TOUCH_SCROLL://正在滚动  
  36.             {  
  37.                 //设置为正在滚动  
  38.                 myAdapter.setScrollState(true);  
  39.                 break;  
  40.             }  
  41.         }  
  42.     }  

最后记得给listview加上滑动的监听

istview.setOnScrollListener(this);

这里写图片描述



  

  综上,listview的优化其实就是去找getView中的耗时操作,然后提取出来,要么使用异步的方式为item的布局设置数据,要是实在需要同步,就只能在Adapter初始化时将数据准备好,然后再getView中只需绑定一下就行。

  1. package com.zhengsonglan.listview_loading.adapter;  
  2.   
  3. import android.content.Context;  
  4. import android.view.LayoutInflater;  
  5. import android.view.View;  
  6. import android.view.ViewGroup;  
  7. import android.widget.BaseAdapter;  
  8. import android.widget.ImageView;  
  9. import android.widget.TextView;  
  10.   
  11. import com.nostra13.universalimageloader.core.ImageLoader;  
  12. import com.zhengsonglan.listview_loading.R;  
  13. import com.zhengsonglan.listview_loading.entity.UserEnity;  
  14.   
  15. import java.util.List;  
  16.   
  17. /** 
  18.  * 
  19.  */  
  20. public class MyAdapter extends BaseAdapter {  
  21.     Context context;  
  22.     LayoutInflater inflater;  
  23.     List<UserEnity> lists;  
  24.   
  25.     private  boolean scrollState=false;  
  26.   
  27.     public void setScrollState(boolean scrollState) {  
  28.         this.scrollState = scrollState;  
  29.     }  
  30.   
  31.   
  32.     public MyAdapter(Context context, List<UserEnity> lists) {  
  33.         this.context=context;  
  34.         this.inflater=LayoutInflater.from(context);  
  35.         this.lists=lists;  
  36.     }  
  37.   
  38.     @Override  
  39.     public int getCount() {  
  40.         return lists!=null?lists.size():0;  
  41.     }  
  42.   
  43.     @Override  
  44.     public Object getItem(int position) {  
  45.         return lists.get(position);  
  46.     }  
  47.   
  48.     @Override  
  49.     public long getItemId(int position) {  
  50.         return position;  
  51.     }  
  52.   
  53.     @Override  
  54.     public View getView(int position, View convertView, ViewGroup parent) {  
  55.         ViewHolder viewHolder;  
  56.         if (convertView == null) {  
  57.             convertView=inflater.inflate(R.layout.main_item,null,true);  
  58.             viewHolder=new ViewHolder();  
  59.             viewHolder.iv_icon= (ImageView) convertView.findViewById(R.id.main_item_iv_icon);  
  60.             viewHolder.tv_name= (TextView) convertView.findViewById(R.id.main_item_tv_name);  
  61.             convertView.setTag(viewHolder);  
  62.         } else {  
  63.             viewHolder= (ViewHolder) convertView.getTag();  
  64.         }  
  65.   
  66.   
  67.         UserEnity userEnity=lists.get(position);  
  68.   
  69.         String img_url=userEnity.getIcon();  
  70.         if (!scrollState){  
  71.             viewHolder.tv_name.setText(userEnity.getName());  
  72.             viewHolder.tv_name.setTag(null);  
  73.             ImageLoader.getInstance().displayImage(img_url,viewHolder.iv_icon);  
  74.             viewHolder.iv_icon.setTag("1");  
  75.   
  76.         }else{  
  77.             viewHolder.tv_name.setText("加载中");  
  78.             viewHolder.tv_name.setTag(userEnity.getName());  
  79.             viewHolder.iv_icon.setTag(img_url);  
  80.             viewHolder.iv_icon.setImageResource(R.mipmap.ic_launcher);  
  81.   
  82.         }  
  83.         return convertView;  
  84.   
  85.     }  
  86.   
  87.     static class ViewHolder{  
  88.         TextView tv_name;  
  89.         ImageView iv_icon;  
  90.     }  
  91. }  

这个Adapter中重要的代码如下:
[java]  view plain  copy   在CODE上查看代码片 派生到我的代码片
  1. //定义当前listview是否在滑动状态  
  2. private  boolean scrollState=false;  
  3. public void setScrollState(boolean scrollState) {  
  4.     this.scrollState = scrollState;  
  5. }  

[java]  view plain  copy   在CODE上查看代码片 派生到我的代码片
  1. //实体类  
  2. UserEnity userEnity=lists.get(position);  
  3.   
  4. if (!scrollState){//如果当前不是滑动的状态,我们填充真数据  
  5.             //填充数据  
  6.             viewHolder.tv_name.setText(userEnity.getName());  
  7.             //设置Tag中数据为空表示数据已填充  
  8.             viewHolder.tv_name.setTag(null);  
  9.             //加载图片  
  10.             ImageLoader.getInstance().displayImage(img_url,viewHolder.iv_icon);  
  11.             //设置tag为1表示已加载过数据  
  12.             viewHolder.iv_icon.setTag("1");  
  13.   
  14. }else{//如果当前是滑动的状态,我们填充假数据  
  15.             viewHolder.tv_name.setText("加载中");  
  16.             //将数据name保存在Tag当中  
  17.             viewHolder.tv_name.setTag(userEnity.getName());  
  18.             //将数据image_url保存在Tag当中  
  19.             viewHolder.iv_icon.setTag(img_url);  
  20.             //设置默认显示图片(最好是本地资源的图片)  
  21.             viewHolder.iv_icon.setImageResource(R.mipmap.ic_launcher);  
  22.   
  23. }  

我们在看看Activity中的代码,主要是监听listview的onscrolllistener方法
[java]  view plain  copy   在CODE上查看代码片 派生到我的代码片
  1. @Override  
  2.     public void onScrollStateChanged(AbsListView view, int scrollState) {  
  3.         switch (scrollState){  
  4.   
  5.             case AbsListView.OnScrollListener.SCROLL_STATE_IDLE://停止滚动  
  6.             {  
  7.                 //设置为停止滚动  
  8.                 myAdapter.setScrollState(false);  
  9.                 //当前屏幕中listview的子项的个数  
  10.                 int count = view.getChildCount();  
  11.                 Log.e("MainActivity",count+"");  
  12.   
  13.                 for (int i = 0; i < count; i++) {  
  14.                     //获取到item的name  
  15.                     TextView tv_name = (TextView) view.getChildAt(i).findViewById(R.id.main_item_tv_name);  
  16.                     //获取到item的头像  
  17.                     ImageView iv_show= (ImageView) view.getChildAt(i).findViewById(R.id.main_item_iv_icon);  
  18.   
  19.                     if (tv_name.getTag() != null) { //非null说明需要加载数据  
  20.                         tv_name.setText(tv_name.getTag().toString());//直接从Tag中取出我们存储的数据name并且赋值  
  21.                         tv_name.setTag(null);//设置为已加载过数据  
  22.                     }  
  23.   
  24.                     if (!iv_show.getTag().equals("1")){//!="1"说明需要加载数据  
  25.                         String image_url=iv_show.getTag().toString();//直接从Tag中取出我们存储的数据image——url  
  26.                         ImageLoader.getInstance().displayImage(image_url, iv_show);//显示图片  
  27.                         iv_show.setTag("1");//设置为已加载过数据  
  28.                     }  
  29.                 }  
  30.                 break;  
  31.             }  
  32.             case AbsListView.OnScrollListener.SCROLL_STATE_FLING://滚动做出了抛的动作  
  33.             {  
  34.                 //设置为正在滚动  
  35.                 myAdapter.setScrollState(true);  
  36.                 break;  
  37.             }  
  38.   
  39.             case AbsListView.OnScrollListener.SCROLL_STATE_TOUCH_SCROLL://正在滚动  
  40.             {  
  41.                 //设置为正在滚动  
  42.                 myAdapter.setScrollState(true);  
  43.                 break;  
  44.             }  
  45.         }  
  46.     }  

最后记得给listview加上滑动的监听

listview.setOnScrollListener(this);

效果

这里写图片描述


                
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
提供的源码资源涵盖了Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 适合毕业设计、课程设计作业。这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。 所有源码均经过严格测试,可以直接运行,可以放心下载使用。有任何使用问题欢迎随时与博主沟通,第一时间进行解答!
提供的源码资源涵盖了小程序应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 适合毕业设计、课程设计作业。这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。 所有源码均经过严格测试,可以直接运行,可以放心下载使用。有任何使用问题欢迎随时与博主沟通,第一时间进行解答!
提供的源码资源涵盖了Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 适合毕业设计、课程设计作业。这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。 所有源码均经过严格测试,可以直接运行,可以放心下载使用。有任何使用问题欢迎随时与博主沟通,第一时间进行解答!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值