Android ListView最佳处理方式,ListView拖动防重复数据显示,单击响应子控件

Android ListView最佳处理方式,ListView拖动防重复数据显示,单击响应子控件。

1、为了防止拖动ListView时,在列表末尾重复数据显示。需要加入 HashMap<Integer,View> lmap = new HashMap<Integer,View>();其中Integer为列表位置,View为子项视图,加入数据前首先if (lmap.get(position)==null)
,满足条件时,加入lmap.put(position, convertView);如果条件不满足,convertView = lmap.get(position);

2、监听每个子控件时,一定要加入final int currentPosition=position;这样可以牢牢抓住每次点击的响应位置;最好把控件集成到类中。

[java] view
plain
copy

  1. package logic;  
  2.   
  3. import java.util.HashMap;  
  4. import java.util.List;  
  5. import java.util.Map;  
  6.   
  7. import logic.PlaceAdapter.ViewHolder;  
  8.   
  9. import org.guiji.BigPictureActivity;  
  10. import org.guiji.ClassUserListActivity;  
  11. import org.guiji.CommentMoodActivity;  
  12. import org.guiji.R;  
  13. import org.guiji.UserHomeActivity;  
  14.   
  15. import support.ClassUserListImageDownloadTask;  
  16. import support.ImageDownloadTask;  
  17. import support.SystemConstant;  
  18. import android.content.Context;  
  19. import android.content.Intent;  
  20. import android.text.Html;  
  21. import android.view.LayoutInflater;  
  22. import android.view.View;  
  23. import android.view.ViewGroup;  
  24. import android.view.View.OnClickListener;  
  25. import android.widget.BaseAdapter;  
  26. import android.widget.ImageView;  
  27. import android.widget.TextView;  
  28.   
  29. public class ClassUserListAdapter extends BaseAdapter {  
  30.     HashMap<Integer,View> lmap = new HashMap<Integer,View>();  
  31.     private LayoutInflater mInflater=null;  
  32.     private List<Map<String, String>> mData=null;  
  33.     private ClassUserListImageDownloadTask imgtask=null;  
  34.     private Context context;  
  35.     public List<Map<String, String>> getmData() {  
  36.         return mData;  
  37.     }  
  38.   
  39.     public void setmData(List<Map<String, String>> mData) {  
  40.         this.mData = mData;  
  41.     }  
  42.     public ClassUserListAdapter(Context context){  
  43.         this.mInflater = LayoutInflater.from(context);  
  44.         this.context=context;  
  45.     }  
  46.     @Override  
  47.     public int getCount() {  
  48.         return mData.size();  
  49.     }  
  50.   
  51.     @Override  
  52.     public Object getItem(int position) {  
  53.         return mData.get(position);  
  54.     }  
  55.   
  56.     @Override  
  57.     public long getItemId(int position) {  
  58.         return position;  
  59.     }  
  60.   
  61.     @Override  
  62.     public View getView(int position, View convertView, ViewGroup parent) {  
  63.         ClassUserListViewHolder holder = null;  
  64.         if (lmap.get(position)==null) {  
  65.             imgtask=new ClassUserListImageDownloadTask();  
  66.               
  67.             convertView = mInflater.inflate(R.layout.classuserlist_item, null);  
  68.             holder=new ClassUserListViewHolder();   
  69.               
  70.             holder.classuserlist_item_userlogo=(ImageView)convertView.findViewById(R.id.classuserlist_item_userlogo);  
  71.             holder.classuserlist_item_username=(TextView)convertView.findViewById(R.id.classuserlist_item_username);  
  72.             holder.classuserlist_item_statuscontent=(TextView)convertView.findViewById(R.id.classuserlist_item_statuscontent);  
  73.             holder.classuserlist_item_idfans1=(TextView)convertView.findViewById(R.id.classuserlist_item_idfans1);  
  74.             holder.classuserlist_item_idfans2=(TextView)convertView.findViewById(R.id.classuserlist_item_idfans2);  
  75.             holder.classuserlist_item_idmood=(TextView)convertView.findViewById(R.id.classuserlist_item_idmood);  
  76.             holder.classuserlist_item_idhuoyuevalue=(TextView)convertView.findViewById(R.id.classuserlist_item_idhuoyuevalue);  
  77.             holder.classuserlist_item_msgpic=(ImageView)convertView.findViewById(R.id.classuserlist_item_msgpic);  
  78.             holder.classuserlist_item_msgcontent=(TextView)convertView.findViewById(R.id.classuserlist_item_msgcontent);  
  79.             holder.classuserlist_item_idtimeplace=(TextView)convertView.findViewById(R.id.classuserlist_item_idtimeplace);  
  80.             holder.classuserlist_item_classbutton=(ImageView)convertView.findViewById(R.id.classuserlist_item_classbutton);  
  81.               
  82.             lmap.put(position, convertView);  
  83.             convertView.setTag(holder);  
  84.               
  85.             holder.classuserlist_item_username.setText((String)mData.get(position).get("username"));  
  86.             if(mData.get(position).get("idstatuscontent")!=null){  
  87.                 holder.classuserlist_item_statuscontent.setText((String)mData.get(position).get("idstatuscontent"));  
  88.                 holder.classuserlist_item_statuscontent.setVisibility(0);  
  89.             }  
  90.             if(mData.get(position).get("idfans1")!=null){  
  91.                 holder.classuserlist_item_idfans1.setText((String)mData.get(position).get("idfans1"));  
  92.                 holder.classuserlist_item_idfans1.setVisibility(0);  
  93.             }  
  94.             if(mData.get(position).get("idfans2")!=null){  
  95.                 holder.classuserlist_item_idfans2.setText((String)mData.get(position).get("idfans2"));  
  96.                 holder.classuserlist_item_idfans2.setVisibility(0);  
  97.             }  
  98.               
  99.             holder.classuserlist_item_idmood.setText((String)mData.get(position).get("idmood"));  
  100.             if(mData.get(position).get("idhuoyuevalue").length()>=4)  
  101.                 holder.classuserlist_item_idhuoyuevalue.setText("活跃值"+"("+mData.get(position).get("idhuoyuevalue").substring(0, 4)+")");  
  102.             else  
  103.                 holder.classuserlist_item_idhuoyuevalue.setText("活跃值"+"("+mData.get(position).get("idhuoyuevalue")+"0"+")");  
  104.               
  105.             if(mData.get(position).get("idmsgcontent")!=null){  
  106.                 holder.classuserlist_item_msgcontent.setText((String)mData.get(position).get("idmsgcontent"));  
  107.                 holder.classuserlist_item_msgcontent.setVisibility(0);  
  108.             }  
  109.             if(mData.get(position).get("idtime")!=null){  
  110.                 holder.classuserlist_item_idtimeplace.setText((String)mData.get(position).get("idtime")+"  "+(String)mData.get(position).get("idplace"));  
  111.                 holder.classuserlist_item_idtimeplace.setVisibility(0);  
  112.             }  
  113.               
  114.             String temp=SystemConstant.baseURLNone+mData.get(position).get("userlogo")+","+  
  115.             SystemConstant.baseURLNone+mData.get(position).get("idmsgpic");  
  116.             imgtask.execute(temp,holder);  
  117.               
  118.         }else {  
  119.             convertView = lmap.get(position);  
  120.             holder = (ClassUserListViewHolder)convertView.getTag();  
  121.         }  
  122.           
  123.         final int currentPosition=position;  
  124.         holder.classuserlist_item_userlogo.setOnClickListener(new OnClickListener() {  
  125.               
  126.             @Override  
  127.             public void onClick(View v) {  
  128.                 MainService.guiji.setCurrentURL(SystemConstant.baseURL+mData.get(currentPosition).get("userLink"));  
  129.                 Intent it=new Intent(context,UserHomeActivity.class);  
  130.                 context.startActivity(it);  
  131.             }  
  132.         });  
  133.           
  134.         holder.classuserlist_item_username.setOnClickListener(new OnClickListener() {  
  135.               
  136.             @Override  
  137.             public void onClick(View v) {  
  138.                 MainService.guiji.setCurrentURL(SystemConstant.baseURL+mData.get(currentPosition).get("userLink"));  
  139.                 Intent it=new Intent(context,UserHomeActivity.class);  
  140.                 context.startActivity(it);  
  141.             }  
  142.         });  
  143.         holder.classuserlist_item_msgpic.setOnClickListener(new OnClickListener() {  
  144.               
  145.             @Override  
  146.             public void onClick(View v) {  
  147.                 MainService.guiji.setCurrentURL(SystemConstant.baseURLNone+mData.get(currentPosition).get("idmsgpic"));  
  148.                 Intent it=new Intent(context,BigPictureActivity.class);  
  149.                 context.startActivity(it);  
  150.             }  
  151.         });  
  152.         holder.classuserlist_item_idfans1.setOnClickListener(new OnClickListener() {  
  153.               
  154.             @Override  
  155.             public void onClick(View v) {  
  156.                 MainService.guiji.deleteReply(SystemConstant.baseURL+mData.get(currentPosition).get("idfans1link"));  
  157.                 ((ClassUserListActivity) context).createTask();  
  158.             }  
  159.         });  
  160.         holder.classuserlist_item_idfans2.setOnClickListener(new OnClickListener() {  
  161.               
  162.             @Override  
  163.             public void onClick(View v) {  
  164.                 MainService.guiji.deleteReply(SystemConstant.baseURL+mData.get(currentPosition).get("idfans2link"));  
  165.                 ((ClassUserListActivity) context).createTask();  
  166.             }  
  167.         });  
  168.           
  169.         holder.classuserlist_item_classbutton.setOnClickListener(new OnClickListener() {  
  170.               
  171.             @Override  
  172.             public void onClick(View v) {  
  173.                 String temp=SystemConstant.baseURL+mData.get(currentPosition).get("idcommentlink");  
  174. //              MainService.guiji.setCurrentURL(temp);  
  175.                 MainService.guiji.setPageType(4);  
  176.                 MainService.guiji.setBackURL(temp);  
  177.                 Intent it=new Intent(context,CommentMoodActivity.class);  
  178.                 context.startActivity(it);  
  179.             }  
  180.         });  
  181.           
  182.         return convertView;  
  183.     }  
  184.     public class ClassUserListViewHolder{  
  185.         public ImageView classuserlist_item_userlogo;  
  186.         public TextView classuserlist_item_username;  
  187.         public TextView classuserlist_item_statuscontent;  
  188.         public TextView classuserlist_item_idfans1;  
  189.         public TextView classuserlist_item_idfans2;  
  190.         public TextView classuserlist_item_idmood;  
  191.         public TextView classuserlist_item_idhuoyuevalue;  
  192.         public ImageView classuserlist_item_msgpic;  
  193.         public TextView classuserlist_item_msgcontent;  
  194.         public TextView classuserlist_item_idtimeplace;  
  195.         public ImageView classuserlist_item_classbutton;  
  196.     }  
  197.   
  198. }  

ListView在开发中是一个经常用的控件,有时候为了扩展更多功能也会用到ExpandableListView,然而数据的正确显示是开发者在实际开发中需要注意的,我在实现ListView的时候,最常遇到的是数据重复显示还有快速滑动的时候数据显示不完整的现象,然而如果在数据量大的时候还涉及到性能和convertView重用的问题。上面的这种处理方式,似乎已经比较好了,我已经验证过,之前滑动列表出现数据重复和显示不完整的现象全都没了。

Android ListView图片显示重复错乱闪烁问题在滑动过程中的解决办法

主要分析Android ListView滚动过程中图片显示重复、错乱、闪烁的原因及解决方法,顺带提及ListView的缓存机制。
1、原因分析
ListView item缓存机制
:为了使得性能更优,ListView会缓存行item(某行对应的View)。ListView通过adapter的getView函数获得每行的item。滑动过程中,

a. 如果某行item已经滑出屏幕,若该item不在缓存内,则put进缓存,否则更新缓存;
b. 获取滑入屏幕的行item之前会先判断缓存中是否有可用的item,如果有,做为convertView参数传递给adapter的getView。
更具体可见源代码ListView.obtainView

 

这样,如下的getView写法就可以充分利用缓存大大提升ListView的性能。即便上万个行item,最多inflate的次数为n,n为一屏最多显示ListView 行item的个数。

ListView Adapter getView写法

<span style="line-height: 20px; background-color: rgb(207, 204, 199);">@Override
public View getView(int position, View convertView, ViewGroup parent) {
    ViewHolder holder;
    if (convertView == null) {
        convertView = inflater.inflate(R.layout.list_item, null);
        holder = new ViewHolder();
        ……
        convertView.setTag(holder);
    } else {
        holder = (ViewHolder)convertView.getTag();
    }
}

/**
 * ViewHolder
 *
 * @author trinea@trinea.cn 2013-08-01
 */
private static class ViewHolder {

    ImageView appIcon;
    TextView  appName;
    TextView  appInfo;
}</span>

这样提升了性能,但同时也会造成另外一些问题:

a. 行item图片显示重复
 这个显示重复是指当前行item显示了之前某行item的图片。
 比如ListView滑动到第2行会异步加载某个图片,但是加载很慢,加载过程中listView已经滑动到了第14行,且滑动过程中该图片加载结束,第2行已不在屏幕内,根据上面介绍的缓存原理,第2行的view可能被第14行复用,这样我们看到的就是第14行显示了本该属于第2行的图片,造成显示重复。

b. 行item图片显示错乱
 这个显示错乱是指某行item显示了不属于该行item的图片。
 比如ListView滑动到第2行会异步加载某个图片,但是加载很慢,加载过程中listView已经滑动到了第14行,第2行已不在屏幕内,根据上面介绍的缓存原理,第2行的view可能被第14行复用,第14行显示了第2行的View,这时之前的图片加载结束,就会显示在第14行,造成错乱。

c. 行item图片显示闪烁
 上面b的情况,第14行图片又很快加载结束,所以我们看到第14行先显示了第2行的图片,立马又显示了自己的图片进行覆盖造成闪烁错乱。

2、解决方法
 通过上面的分析我们知道了出现错乱的原因是异步加载及对象被复用造成的,如果每次getView能给对象一个标识,在异步加载完成时比较标识与当前行item的标识是否一致,一致则显示,否则不做处理即可。
 下面以使用ImageCache为ListView提供图片获取缓存为例,ListView中强烈推荐使用ImageCache。
 首先在listview adapter的getView中添加

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    ViewHolder holder;
    if (convertView == null) {
        convertView = inflater.inflate(R.layout.list_item, null);
        holder = new ViewHolder();
        ……
        convertView.setTag(holder);
    } else {
        holder = (ViewHolder)convertView.getTag();
    }

    ……
    // add tag for image, to compare it when image loaded finish
    imageView.setTag(imageUrl);
    // if not in cache, restore default
    if (!Cache.ICON_CACHE.get(imageUrl, imageView)) {
        imageView.setImageDrawable(null);
    }
}

其中setTag表示设置标识,方便下面进行标志比对

if (!Cache.ICON_CACHE.get(imageUrl, imageView))

1

if
(!Cache.ICON_CACHE.get(imageUrl,
imageView))

Cache.ICON_CACHE为ImageCache的实例,表示如果不在缓存内则设置drawable为null(当然你可以可以设置为你自己的默认资源),防止显示了之前某个行item的图片,解决了a.
行item图片显示重复问题。

 

在ImageCache的OnImageCallbackListener的onGetSuccess函数中添加

Java

public void onGetSuccess(String imageUrl, Drawable imageDrawable, View view, boolean isInCache) {
// can be another view child, like textView and so on
if (view != null && imageDrawable != null) {
ImageView imageView = (ImageView)view;
// add tag judge, avoid listView cache and so on
String imageUrlTag = (String)imageView.getTag();
if (ObjectUtils.isEquals(imageUrlTag, imageUrl)) {
imageView.setImageDrawable(imageDrawable);
}
}
};

1

2

3

4

5

6

7

8

9

10

11

public
void onGetSuccess(String
imageUrl,
Drawable imageDrawable,
View view,
boolean isInCache)
{

    // can be another view child, like textView and so on

    if
(view
!= null
&& imageDrawable
!= null)
{

        ImageView imageView
= (ImageView)view;

        // add tag judge, avoid listView cache and so on

        String
imageUrlTag =
(String)imageView.getTag();

        if
(ObjectUtils.isEquals(imageUrlTag,
imageUrl))
{

            imageView.setImageDrawable(imageDrawable);

        }

    }

};

在上面用String imageUrlTag = (String)imageView.getTag();取得之前设置的tag,然后和当前的url进行比较,如果相等则显示,解决了b. 行item图片显示错乱,c. 行item图片显示错乱的两个问题。其中ObjectUtils可见ObjectUtils@Github.

其他异步加载过程解决原理类似。

时间: 2024-10-06 04:53:40

Android ListView最佳处理方式,ListView拖动防重复数据显示,单击响应子控件的相关文章

Android ListView中子控件的状态保存以及点击子控件改变子控件状态

这两天用到了ListView,写下遇到的一些问题.首先是ListView本身与子控件的焦点问题,比如我这里子控件用到了Button,在需要ListView中的根布局属性上加上下面的这一个属性: [html] view plaincopy android:descendantFocusability="blocksDescendants"   用于屏蔽子控件抢夺ListView的焦点,也可在Button本身设置焦点属性为false.其它的一些控件的点击问题就不说了,网上有很多. 然后是需

ListView 子控件单击事件混乱

问题描述 ListView 子控件单击事件混乱 由于覆用convertview导致子控件单击事件混乱,例如单击第一个按钮的时候,下面看不到的第七个按钮也响应了单击事件,怎么写单击事件可以不发生这种混乱呢?有没有demo给个,谢谢. 解决方案 给个邮箱吧 解决方案二: 1.是Android就写清楚,因为无数个语言或者架构中都有listView: 2.尽量贴出代码. 解决方案三: onitemclick事件不是onclick事件,看看可不可能是这个问题 解决方案四: 不好意思,可能是我搞错了,你是a

解决ListView中的Item点击事件和子控件的冲突或者item点击没有反应

fragment中添加了button和checkbox这些控件,此时这些子控件会将焦点获取到,所以常常当点击item时变化的是子控件,item本身的点击没有响应. 这时候就可以使用descendantFocusability来解决啦,API描述如下: android:descendantFocusability 该属性是当一个为view获取焦点时,定义viewGroup和其子控件两者之间的关系. 属性的值有三种: beforeDescendants:viewgroup会优先其子类控件而获取到焦点

listview-关于ListView与子控件焦点的问题,出现了两个焦点?

问题描述 关于ListView与子控件焦点的问题,出现了两个焦点? 大家遇到这个情况没?怎么会有两个焦点呢????? 我现在希望,焦点只在播放按钮和闹铃按钮间切换.请大神给点思路呀.... 再补充下现象:名词解释:假焦点:左边的textview.真焦点:"play"button.我用遥控器下移动的时候,假焦点会移动到Item的 textview,真焦点移动到"play"Button上.再按"下",移动到下一个item的textview,真焦点不动

asp.net 后台访问listview内子控件

问题描述 asp.net 后台访问listview内子控件 设置一个button按钮,点击时读取listview里一个label控件的文本,使用了findcontrol方法且出错,显示未引用实例,请问该怎么办? 解决方案 listview里面的,先得到rows,再得到cell

Android中实现HorizontalScrollView内子控件横向拖拽

前言 网上ListView上下拖动的例子有,效果也很好,但是项目要横着拖的,只要硬着头皮自己写(主要是没找到合适的),参考文章1修改而来,分享一下. 截图 代码 java public class HoDragActivity extends Activity { private LinearLayout main; private GestureDetector mGestureDetector; @Override public void onCreate(Bundle savedInsta

Android HorizontalScrollView内子控件横向拖拽实例代码_Android

前言         网上ListView上下拖动的例子有,效果也很好,但是项目要横着拖的,只要硬着头皮自己写(主要是没找到合适的),参考文章1修改而来,分享一下. 正文 截图 实现代码: public class HoDragActivity extends Activity { private LinearLayout main; private GestureDetector mGestureDetector; @Override public void onCreate(Bundle s

Android设置viewGroup和其子控件两者之间的焦点关系

在开发过程中,你可能会遇到这样的问题:在一个很长的界面刚初始化结束的时候默认不是最顶部而是某一个控件,比如ListView:也可能遇到Edittext自己弹出软键盘的问题等等.其实这些都是焦点获取的问题,不想有这样的小bug那么就要对焦点的获取问题进行合理的控制.大多数人会在初始化的时候就对某个控件添加这个属性: ×××.setFocusable(false); 其实在建立xml布局文件的时候Android就提供了焦点控制的属性: android:descendantFocusability="

Android自定义ViewGroup之子控件的自动换行和添加删除

常用的布局类型并不能满足所有需求,这时就会用到ViewGroup. ViewGroup作为一个放置View的容器,并且我们在写布局xml的时候,会告诉容器(凡是以layout为开头的属性,都是为用于告诉容器的),我们的宽度(layout_width).高度(layout_height).对齐方式(layout_gravity)等:当然还有margin等:于是乎,ViewGroup需要做的事情是:给childView计算出建议的宽和高和测量模式 :决定childView的位置:为什么只是建议的宽和