listView 的加载问题,及优化,notifyDataSetChanged()的相关问题

1、listView在开始绘制的时候,系统首先调用getCount()函数,得到全部数据,根据他的返回值得到listView的长度,然后根据这个长度,调用getView()逐一绘制每一行,当然这里如果count个数比较大的时间,一页显示不玩的情况下,并不会调用所有的getView()函数,只会调用显式在屏幕上对应位置的getView();如果你的getCount()返回值是0的话,列表将不显示同样 return 1,就只显示一行。
2、ListView中getView()方法重复调用的问题:这个问题理解起来比较复杂,简单地说就是ListView布局时height和width都不是fill_parent,导致不断计算高度,不断刷新。或者说它的父容器没有设置成fill_parent;那么简单的解决这个问题的方法就是把他们的布局设置为fill_parent
3.接下来先说一下getView(int position, View convertView, ViewGroup parent)中的convertView参数,谷歌官方的解释是:
convertView - The old view to reuse, if possible. Note: You should check that this view is non-null and of an appropriate type before using. If it is not possible to convert this view to display the correct data, this method can create a new view. Heterogeneous lists can specify their number of view types, so that this View is always of the right type (see Adapter.getViewTypeCount() and Adapter.getItemViewType(int)).

大致的意思就是convertView是用来重用View的,如果没有View来显示数据的话,会先创建一个View;如果这个view已经存在而且里面没值了,就会被用来重新使用,在网上拷贝了张图:


当item1被移除屏幕的时候 我们会重新new一个View给新显示的item_new 而如果使用了这个convertView 我们其实可以复用它 这样就省去了new View的大量开销

public View getView(int position, View convertView, ViewGroup parent) {
View view = null;
if (convertView != null) {
view = convertView;
//复用了回收的view 只需要直接作内容填充的修改就好了
} else {
view = new Xxx(...);
//没有供复用的view 按一般的做法新建view
}
return view;
}
4、那么说了 convertView就该说说listview 的优化了, 当listview有大量的数据需要加载的时候,会占据大量内存,影响性能,这时候就需要按需填充并重新使用view来减少对象的创建。
public View getView(int position, View convertView, ViewGroup parent) {
 if (convertView == null) {
   convertView = mInflater.inflate(R.layout.item, parent, false);
 }
   ((TextView) convertView.findViewById(R.id.text)).setText(DATA[position]);
   ((ImageView) convertView.findViewById(R.id.icon)).setImageBitmap(
   (position & 1) == 1 ? mIcon1 : mIcon2);
   return convertView;
 }
 
 
 
这种方式里面,我们通过converview找到对应需要修改的text和ico,然后修改数据,进行返回。
5、接下来我们来看看谷歌推荐的优化方式:
public View getView(int position, View convertView, ViewGroup parent) {
        Log.e(TAG, "getView --> " + position);
        // 1、指定每一行的布局;2、指定每一行布局绑定的数据
        //convertView:表示每一行返回的布局
        //加载第一行数据时,convertView为空,从第二行开始,都使用第一行指定的布局
        if (convertView == null) {
            convertView = mInflater.inflate(R.layout.item, null);
            viewHolder = new ViewHolder();
            //指定每一行布局的具体图片和文本
            viewHolder.imageView = (ImageView) convertView.findViewById(R.id.imageView);
            viewHolder.textView = (TextView) convertView.findViewById(R.id.textView);
          
            convertView.setTag(viewHolder);
        } else {
            viewHolder = (ViewHolder) convertView.getTag();
        }     
  viewHolder.imageView.setImageResource(list.get(position).getImageIndex());
            viewHolder.textView.setText(list.get(position).getText());           
        return convertView;
    }
    
    //视图缓存优化
    class ViewHolder{
        ImageView imageView;
        TextView textView;        
    }  
然后用convertView.setTag(holder)的方式将之前通过findViewById找到的textview与ImageView放入converivew对象中。
这样当再次重用converview的时候,就不必再次利用findViewById来查找了,省掉了开销。
7、adapter 的notifyDataSetChanged()无法正常更新:
otifyDataSetChanged方法通过一个外部的方法控制如果适配器的内容改变时需要强制调用getView来刷新每个Item的内容。但如果我们在得到适配器内容时再次新建时就会到时 otifyDataSetChanged监测到变化后,刷新界面时会把数据更新到界面,但要注意,此时塞到界面的那个List<T>对象仍然是你第一次创建的那个,而不是你又重新创建的。也就是说出现的原因是因为我们把要塞到界面的 List<T>对象改变了。下面看一发谷歌官方的解释:
 /**
     * Notifies the attached observers that the underlying data has been changed
     * and any View reflecting the data set should refresh itself.
     */ 
当出现这种问题时的解决方案:
1)、 重新加载适配器:但这种方法就无所谓什么节省资源了
adapter = new YouhuaAdapt(users,BaseAdaptTest.this);
usersListView.setAdapter(adapter);  

2)、对于那种每次过来不同对象的情况,可以在Avtivity中自己创建一个对象;然后每次数据过来的时间就只更新改对象内内容:

users.clear();
users.addAll(userDao.queryPage(count, PageTotal)); 

8、注意一下如果我们在ListView的页尾中添加了进度条,并且使用了progressBar.setVisibility(View.GONE);属性的话,就会自动刷新页面

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值