前面我们的问题是,当Listview加载数据量比较大时,会出现OOM异常,因为每个item都占了一块内存,item达到一定量的时候,内存就被占满了,导致了内存溢出,那么 我们就要对Listview来进行优化,因为我们的屏幕能显示的item条数是有限的,所以我们划出屏幕的item就可以回收给下一个item来使用,只需要修改里面的数据就可以了,思路就是这样,然后我们看getView方法里面有一个参数,就是第二个参数 View类型的convertView,这个就是表示我们刚刚划出屏幕的item,当item1滚出屏幕,并且一个新的项目从屏幕地段上来时,ListView再请求一个type1视图。convertView此时不是空值了,它的值是item1.你只需要设定新的数据返回convertView,不必重新创建一个视图。这样直接使用convertView从而减少了很不不必要view的创建。这就是我们优化Listview的思路,我们用一个类,包含item
里面的每个控件,作为一个对象,当convertView为空的时候去findViewByid,不为空时,直接拿到convertView里面的控件,修改数据就可以了,下面是优化过后的适配器代码
@Override public View getView(int position, View convertView, ViewGroup parent) { ViewHolder holder=null; //当convertView为空的时候,findViewByid赋值给ViewHolder if (null==convertView) { holder=new ViewHolder(); convertView = mInflater.inflate(R.layout.my_listview_item, null);//通过mInflater来加载布局 holder.iv = (ImageView) convertView.findViewById(R.id.iv);//找到对应的控件 //把holder设置为convertView的标记 convertView.setTag(holder); }else { //当convertView不为空的时候,从convertView拿到标记,也就是holder holder = (ViewHolder) convertView.getTag(); } //拿到holder对象里面的控件进行数据加载 MyAsyncTask myAsyncTask = new MyAsyncTask(holder.iv); myAsyncTask.execute(list.get(position)); return convertView; } /** * viewHolder保存每一个item里面的控件 */ class ViewHolder{ ImageView iv;//每个item的控件 }
这时候我们就避免了数据量过多引起的OOM异常,但我们会发现,会出现图片错位,过一会又跳到显示正确的图片的情况,这是因为我们是复用的上一个划出屏幕的控件里面包含有数据,新的数据加载进入需要网络,会消耗时间,所以会出现前面的图片显示在控件上,过一会又显示新的图片的问题,所以现在我们需要解决图片的错位的问题,我们的思路也是给TmageView来设置一个标记,当我们当前的标记不等于我们预设的标记的时候,就显示我们预设的图片,防止错位。下面是最终代码,
@Override public View getView(int position, View convertView, ViewGroup parent) { ViewHolder holder=null; //当convertView为空的时候,findViewByid赋值给ViewHolder if (null==convertView) { holder=new ViewHolder(); convertView = mInflater.inflate(R.layout.my_listview_item, null);//通过mInflater来加载布局 holder.iv = (ImageView) convertView.findViewById(R.id.iv);//找到对应的控件 //把holder设置为convertView的标记 convertView.setTag(holder); }else { //当convertView不为空的时候,从convertView拿到标记,也就是holder holder = (ViewHolder) convertView.getTag(); } String url=list.get(position); //拿到标记 String tag = (String) holder.iv.getTag(); //当标记不一样的时候,显示默认的图片 if ( url!=tag) { // 预设一个图片 holder.iv.setImageResource(R.mipmap.ic_launcher); //设置标记tag holder.iv.setTag(url); } //拿到holder对象里面的控件进行数据加载 MyAsyncTask myAsyncTask = new MyAsyncTask(holder.iv); myAsyncTask.execute(list.get(position)); return convertView; }
这样就解决了错位的问题,看效果
当图片还没有加载的时候,就显示默认的图片,加载完后,再显示,好了,这次的优化就到这,下次再见咯