`
lansuiyun
  • 浏览: 28321 次
  • 性别: Icon_minigender_1
  • 来自: 广州
社区版块
存档分类
最新评论

listView中多个listItem布局时 convertView缓存及使用(转)

 
阅读更多

最近有需求需要在listView中载入不同的listItem布局,开始没有使用convertView,加载了多个item后导致了内存泄露,所以回来研究convertView在多个listItem布局时的缓存及应用,并且和大家分享

构造Adapter时,没有使用缓存的 convertView,导致内存泄露

示例代码:
public View getView(int position, View convertView, ViewGroup parent) {
  View view = new Xxx(...);
  ... ...
  return view;
}


描述:
  
以构造ListViewBaseAdapter为例,在BaseAdapter中提供了方法:



public View getView(int position, View convertView, ViewGroup parent){ }


来向ListView提供每一个item所需要的view对象。初始时ListView会从BaseAdapter中根据当前的屏幕布局实例化一定数量的view对象,同时ListView会将这些view对象缓存起来。当向上滚动ListView时,原先位于最上面的list itemview对象会被回收,然后被用来构造新出现的最下面的list item。这个构造过程就是由getView()方法完成的,getView()的第二个形参View convertView就是被缓存起来的list itemview对象(初始化时缓存中没有view对象则convertViewnull)
  
由此可以看出,如果我们不去使用convertView,而是每次都在getView()中重新实例化一个View对象的话,即浪费资源也浪费时间,也会使得内存占用越来越大。

修正示例代码:
public View getView(int position, View convertView, ViewGroup parent) {
  View view = null;
  if (convertView != null) {
  view = convertView;
  ...
  } else {
  view = new Xxx(...);
  ...
  }
  return view;
}

上述代码很好的解决了内存泄露的问题,使用convertView回收一些布局供下面重构是使用。

但是如果出现如下图的需求,convertView就不太好用了,convertViewItem为单一的布局时,能够回收并重用,但是多个Item布局时,convertView的回收和重用会出现问题。





Listview中有3Item布局,即使convertView缓存了一些布局,但是在重构时,根本不知道怎么样去让convertView返回你所需要的布局,这时你需要让adapter知道我当前有哪些布局,我重构Item时的布局选取规则,好让convertView能返回你需要的布局

需要重写一下两个函数

@Override

public int getItemViewType(int position) {}

官网解释如下,不解释了
Get the type of View that will be created by getView(int, android.view.View, android.view.ViewGroup)]getView(int, View, ViewGroup) for the specified item.

Parameters
position The position of the item within the adapter's data set whose view type we want.

Returns


  • An integer representing the type of View. Two views should share the same type if one can be converted to the other in getView(int, android.view.View, android.view.ViewGroup)getView(int, View, ViewGroup). Note: Integers must be in the range 0 to getViewTypeCount() - 1. IGNORE_ITEM_VIEW_TYPEcan also be returned.



@Override

public int getViewTypeCount() {}


Get the type of View that will be created by getView(int, android.view.View, android.view.ViewGroup)getView(int, View, ViewGroup) for the specified item.

Parameters
position The position of the item within the adapter's data set whose view type we want.

Returns


  • An integer representing the type of View. Two views should share the same type if one can be converted to the other in getView(int, android.view.View, android.view.ViewGroup)getView(int, View, ViewGroup). Note: Integers must be in the range 0 to getViewTypeCount() - 1. IGNORE_ITEM_VIEW_TYPEcan also be returned.




上述两个函数的作用这如它的名字,得到Item的样式,得到所有的样式数量

下面直接上代码,就是上图的实现代码:

package com.bestv.listViewTest;

import java.util.ArrayList;

import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.CheckBox;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.TextView;

public class listViewTest extends Activity {
/** Called when the activity is first created. */
ListView listView;
MyAdapter listAdapter;
ArrayList<String> listString;

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
listView = (ListView)this.findViewById(R.id.listview);
listString = new ArrayList<String>();
for(int i = 0 ; i < 100 ; i++)
{
listString.add(Integer.toString(i));
}
listAdapter = new MyAdapter(this);
listView.setAdapter(listAdapter);
}

class MyAdapter extends BaseAdapter{

Context mContext;
LinearLayout linearLayout = null;
LayoutInflater inflater;
TextView tex;
final int VIEW_TYPE = 3;
final int TYPE_1 = 0;
final int TYPE_2 = 1;
final int TYPE_3 = 2;

public MyAdapter(Context context) {
// TODO Auto-generated constructor stub
mContext = context;
inflater = LayoutInflater.from(mContext);
}

@Override
public int getCount() {
// TODO Auto-generated method stub
return listString.size();
}

//每个convert view都会调用此方法,获得当前所需要的view样式
@Override
public int getItemViewType(int position) {
// TODO Auto-generated method stub
int p = position%6;
if(p == 0)
return TYPE_1;
else if(p < 3)
return TYPE_2;
else if(p < 6)
return TYPE_3;
else
return TYPE_1;

}

@Override
public int getViewTypeCount() {
// TODO Auto-generated method stub
return 3;
}

@Override
public Object getItem(int arg0) {
// TODO Auto-generated method stub
return listString.get(arg0);
}

@Override
public long getItemId(int position) {
// TODO Auto-generated method stub
return position;
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {
// TODO Auto-generated method stub
viewHolder1 holder1 = null;
viewHolder2 holder2 = null;
viewHolder3 holder3 = null;
int type = getItemViewType(position);


//无convertView,需要new出各个控件
if(convertView == null)
{ 
Log.e("convertView = ", " NULL");

//按当前所需的样式,确定new的布局
switch(type)
{
case TYPE_1:
convertView = inflater.inflate(R.layout.listitem1, parent, false);
holder1 = new viewHolder1();
holder1.textView = (TextView)convertView.findViewById(R.id.textview1);
holder1.checkBox = (CheckBox)convertView.findViewById(R.id.checkbox);
Log.e("convertView = ", "NULL TYPE_1");
convertView.setTag(holder1);
break;
case TYPE_2:
convertView = inflater.inflate(R.layout.listitem2, parent, false);
holder2 = new viewHolder2();
holder2.textView = (TextView)convertView.findViewById(R.id.textview2);
Log.e("convertView = ", "NULL TYPE_2");
convertView.setTag(holder2);
break;
case TYPE_3:
convertView = inflater.inflate(R.layout.listitem3, parent, false);
holder3 = new viewHolder3();
holder3.textView = (TextView)convertView.findViewById(R.id.textview3);
holder3.imageView = (ImageView)convertView.findViewById(R.id.imageview);
Log.e("convertView = ", "NULL TYPE_3");
convertView.setTag(holder3);
break;
}
}
else
{
//有convertView,按样式,取得不用的布局
switch(type)
{
case TYPE_1:
holder1 = (viewHolder1) convertView.getTag();
Log.e("convertView !!!!!!= ", "NULL TYPE_1");
break;
case TYPE_2:
holder2 = (viewHolder2) convertView.getTag();
Log.e("convertView !!!!!!= ", "NULL TYPE_2");
break;
case TYPE_3:
holder3 = (viewHolder3) convertView.getTag();
Log.e("convertView !!!!!!= ", "NULL TYPE_3");
break;
}
}

//设置资源
switch(type)
{
case TYPE_1:
holder1.textView.setText(Integer.toString(position));
holder1.checkBox.setChecked(true);
break;
case TYPE_2:
holder2.textView.setText(Integer.toString(position));
break;
case TYPE_3:
holder3.textView.setText(Integer.toString(position));
holder3.imageView.setBackgroundResource(R.drawable.icon);
break;
}


return convertView;
}

}


//各个布局的控件资源

class viewHolder1{
CheckBox checkBox;
TextView textView;
}
class viewHolder2{
TextView textView;
}
class viewHolder3{
ImageView imageView;
TextView textView;
}
}
   在getView()中需要将不同布局进行缓存和适配,系统在判断是否有convertView时,会自动去调用getItemViewType (int position) ,查看是否已经有缓存的该类型的布局,从而进入if(convertView == null)和else{}的判断。期间需要做的是convertView.setTag(holder3),以便在convertView重用时可以直接拿到该布局的控件,holder3 = (viewHolder3) convertView.getTag()。到这一步,convertView的回收和重用就已经写好了,接下来只需要对你的不同的控件进行设置就行了。
分享到:
评论
2 楼 a379933101 2012-07-13  
哦,没看清,原来是缓冲中的呀
1 楼 a379933101 2012-07-13  
getItemViewType有必要用吗,getItemViewType不就是判断positon吗,在getView中不是有个position吗,直接使用position判断不更直接?

相关推荐

    listView中多个listItem布局时,convertView缓存及使用

    在处理多个listItem布局时,为了提高性能和效率,ListView引入了convertView机制。这个机制是通过缓存已创建但不再可视的listItem视图来避免频繁地创建新视图。下面我们将详细探讨convertView的工作原理及其在实际...

    ListView动态加载listitem

    ListView是Android平台中一个常用的控件,用于展示大量的数据列表,尤其在数据量大到无法一次性加载全部内容时,动态加载listitem(也称为“懒加载”)就显得尤为重要。这种技术可以显著提高应用的性能,减少内存...

    2011.08.26——— android ListView之多个item布局

    这篇博客"2011.08.26——— android ListView之多个item布局"深入探讨了如何在ListView中实现多个不同类型的Item布局,这对于创建动态、丰富的用户界面至关重要。在Android应用设计中,ListView通常用于显示如联系人...

    ListView中含有多个item布局的处理

    在处理多个布局时,首先我们需要定义不同的ViewHolder类,每个ViewHolder对应一种布局。ViewHolder模式是提高ListView性能的一种常见方法,它通过复用视图减少对象创建和布局绘制的时间。例如,可以创建...

    ListView加载多个布局

    然而,标题"ListView加载多个布局"表明我们讨论的是如何在一个ListView中加载并显示不同的视图类型。这通常是通过在ListView中实现自定义适配器(Adapter)来完成的,以满足复杂的数据结构和界面需求。下面将详细...

    Duilib中 ListItem布局切换效果实现

    ListView是包含多个ListItem的容器,每个ListItem代表列表中的一个条目。我们可以通过设置ListItem的各种属性来改变其外观和行为。 接着,我们要关注的是事件处理。Duilib提供了丰富的事件机制,如鼠标点击事件...

    ListView更新ListItem的Demo

    这个“ListView更新ListItem的Demo”旨在演示如何高效地更新ListView中的单个或多个列表项,提高用户体验。通过理解并实践这个Demo,开发者可以更好地掌握ListView的工作原理以及如何优化其性能。 首先,我们来看...

    Android完美解决listview中多个edittext显示混乱问题

    然而,在ListView中嵌套多个EditText时,常常会遇到一个问题,即用户在EditText中输入内容时,ListView滚动时导致显示混乱,原本输入的位置与EditText不匹配,这被称为“EditText焦点错乱”或“ListView复用机制问题...

    ListView列表中播放多个视频

    当需要在一个ListView中播放多个视频时,这通常涉及到自定义Adapter、优化性能和处理播放状态等多个技术要点。下面将详细讲解如何实现这一功能。 首先,我们需要创建一个自定义的ListView Adapter。Adapter是连接...

    android ListView 网格布局

    3. 在Activity中使用GridView:在你的Activity中,实例化GridView并设置Adapter。同时,你还需要为GridView设置列数,这可以通过`setNumColumns()`方法实现。 ```java GridView gridView = findViewById(R.id....

    ListView性能优化之视图缓存

    为了优化 ListView 的性能,我们可以使用 convertView 机制,将已经显示的视图缓存在内存中,以便在下一次显示时直接使用。同时,我们还可以使用 ViewHolder 模式,使用一个固定的视图 holder 来保存视图的状态,...

    android listView中显示不同的布局

    在许多场景下,开发者需要在ListView中显示不同的布局,比如在一个消息列表中,上行消息与下行消息的布局可能不同,这就是所谓的“聊天布局”。本篇将详细介绍如何在Android的ListView中实现这种功能,并基于提供的...

    listview加载多个布局文件

    listview加载多个布局文件,代码分主Activity和适配器两部分,布局文件就不写了,相信大家会写

    ListView加载多item布局

    当我们需要在一个ListView中展示多种不同类型的item布局时,这就涉及到"ListView加载多item布局"的技术。本教程将深入探讨如何实现这一功能,并结合性能优化策略,使ListView在处理大量数据时仍能保持流畅的用户体验...

    Android 解决ListView里面多套布局多个EditText数据混乱问题,附demo

    通过学习和理解以上知识点,开发者可以有效地避免在ListView中使用多套布局和多个EditText时出现的数据混乱问题。同时,这也是一种提升用户体验和应用稳定性的关键技巧。在实际开发过程中,还需要注意测试不同...

    ListView中显示不同的视图布局实现重用Demo

    默认情况下,ListView中的每个项都使用相同的视图布局,但通过自定义Adapter,我们可以为不同的数据项设置不同的视图。 实现这个功能的关键在于`getView()`方法,这是Adapter的核心方法。在这个方法中,我们需要...

    ListView Item多布局的实现

    然而,有时我们不仅仅满足于单一的列表项布局,而是希望在同一个ListView中展示多种不同的布局,这就是所谓的"ListView Item多布局"。这种功能可以使得应用界面更加丰富多彩,提供更好的用户体验。本文将详细介绍...

    ListView加载多种布局

    然而,有些情况下我们不仅需要展示单一类型的条目,还可能需要在同一个ListView中混合显示多种布局。本教程将详细讲解如何在ListView中实现这种功能。 首先,我们需要理解ListView的工作原理。ListView通过Adapter...

    安卓listview相关相关-listview获取网络图片缓存优化.zip

    ListView通过复用convertView(即ViewHolder模式)来提高性能,但这同时也意味着同一视图可能被多次重用,需要在每次显示时更新正确的内容。如果图片加载不当,就可能出现图片错位的问题。 针对这个问题,资料包中...

Global site tag (gtag.js) - Google Analytics