Android开发中ListView实现Item局部刷新

对于ListView数据的刷新大家都知道,改变Adapter的数据源,然后调用Adapter的notifyDateSetChanged()方法即可。

但是在做公司项目的时候,有个下载模块,因为可能同时下载好几个数据,所以用的listview展示所有正在下载的内容。因为下载进度要实时更新,所以要不停的调用notifyDateSetChanged刷新数据。这样会不停的重新绘制整个listview的界面,性能开销非常大。而且如果每个item有图片的话,每个item的图片都需要重新加载,就算图片做了内存缓存,刷新一下图片也会闪一下,不停的刷新就会导致各个item的图片不停的闪,体验一点都不好。

那么对于上面问题,有没有解决办法呢?当然是有的。我们可以针对某一个item进行局部更新,而不影响其它没有修改的item。那么具体如何实现的呢?我们看下面的代码。

private void updateView(int itemIndex) {
    //得到第一个可显示控件的位置,
    int visiblePosition = mListView.getFirstVisiblePosition();
    //只有当要更新的view在可见的位置时才更新,不可见时,跳过不更新
    if (itemIndex - visiblePosition >= 0) {
        //得到要更新的item的view
        View view = mListView.getChildAt(itemIndex - visiblePosition);
        //调用adapter更新界面
        mAdapter.updateView(view, itemIndex);
    }
}

这个函数主要是根据传入的itemIndex来获取第itemIndex的数据所显示的view。itemIndex就是要修改的数据再List集合中的位置,比如我这里下载进度有更新,发了一个广播这里接收到了,需要修改该下载内容的进度条,广播接收器可以这么写:

@Override
public void onReceive(Context context, Intent intent) {
    AppContent appContent = intent.getParcelableExtra("appContent");
    if(appContent == null) return;
    int itemIndex = 0;
    for(AppContent appContent1 : mList) {
        if(appContent.getUrl().equals(appContent1.getUrl())) {
            itemIndex = mList.indexOf(appContent1);
            appContent1.setDownloadPercent(appContent.getDownloadPercent());
            break;
        }
    }
    updateView(itemIndex);
}

下面看Adapter的具体代码:

public class AppContentAdapter extends BaseAdapter{

    private List<AppContent> mDates = null;
    private Context mContext;

    public AppContentAdapter(Context context) {
        this.mContext = context;
    }

    @Override
    public int getCount() {
        return mDates.size();
    }

    @Override
    public Object getItem(int position) {
        return mDates.get(position);
    }

    @Override
    public long getItemId(int position) {
        return position;
    }

    public void setDates(List<AppContent> mDates) {
        this.mDates = mDates;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        ViewHolder holder = null;
        if (convertView == null) {
            holder = new ViewHolder();
            convertView = LayoutInflater.from(mContext).inflate(
                    R.layout.listitem_download, null);
            holder.statusIcon = (DownloadPercentView) convertView.findViewById(R.id.status_icon);
            holder.name = (TextView) convertView.findViewById(R.id.name);
            holder.downloadPercent = (TextView) convertView.findViewById(R.id.download_percent);
            holder.progressBar = (ProgressBar) convertView.findViewById(R.id.progressbar);
            convertView.setTag(holder);
        } else {
            holder = (ViewHolder) convertView.getTag();
        }
        setData(holder, position);
        return convertView;
    }

    /**
     * 设置viewHolder的数据
     * @param holder
     * @param itemIndex
     */
    private void setData(ViewHolder holder, int itemIndex) {
        AppContent appContent = mDates.get(itemIndex);
        holder.name.setText(appContent.getName());
        holder.progressBar.setProgress(appContent.getDownloadPercent());
        setIconByStatus(holder.statusIcon, appContent.getStatus());
        if(appContent.getStatus() == AppContent.Status.PENDING) {
            holder.downloadPercent.setVisibility(View.INVISIBLE);
        } else {
            holder.downloadPercent.setVisibility(View.VISIBLE);
            holder.statusIcon.setProgress(appContent.getDownloadPercent());
            holder.downloadPercent.setText("下载进度:" + appContent.getDownloadPercent() + "%");
        }
    }

    /**
     * 局部刷新
     * @param view
     * @param itemIndex
     */
    public void updateView(View view, int itemIndex) {
        if(view == null) {
            return;
        }
        //从view中取得holder
        ViewHolder holder = (ViewHolder) view.getTag();
        holder.statusIcon = (DownloadPercentView) view.findViewById(R.id.status_icon);
        holder.name = (TextView) view.findViewById(R.id.name);
        holder.downloadPercent = (TextView) view.findViewById(R.id.download_percent);
        holder.progressBar = (ProgressBar) view.findViewById(R.id.progressbar);
        setData(holder, itemIndex);
    }

    /**
     * 根据状态设置图标
     * @param downloadPercentView
     * @param status
     */
    private void setIconByStatus(DownloadPercentView downloadPercentView, AppContent.Status status) {
        downloadPercentView.setVisibility(View.VISIBLE);
        if(status == AppContent.Status.PENDING) {
            downloadPercentView.setStatus(DownloadPercentView.STATUS_PEDDING);
        }
        if(status == AppContent.Status.DOWNLOADING) {
            downloadPercentView.setStatus(DownloadPercentView.STATUS_DOWNLOADING);
        }
        if(status == AppContent.Status.WAITING) {
            downloadPercentView.setStatus(DownloadPercentView.STATUS_WAITING);
        }
        if(status == AppContent.Status.PAUSED) {
            downloadPercentView.setStatus(DownloadPercentView.STATUS_PAUSED);
        }
        if(status == AppContent.Status.FINISHED) {
            downloadPercentView.setStatus(DownloadPercentView.STATUS_FINISHED);
        }
    }

    private class ViewHolder {
        private DownloadPercentView statusIcon;
        private TextView name;
        private TextView downloadPercent;
        private ProgressBar progressBar;
    }
}

ListView中 局部刷新Item 实现下载进度条局部更新

当更新当前正在下载的任务的时候,使用 notifyDataSetChanged();方法会使整个页面都会刷新。

而且进度更新比较频繁,这就造成了内存的消耗和页面卡顿(在进度更新很频繁的情况),笔者甚至出现了卡住页面无法进行操作的情况。

所以想到了能不能局部刷新某个Item。也查了下资料,问题解决。

解决思路:

通过listview.getFirstVisiblePosition()方法获取到显示的item的首个位置 ,再根据position, 计算出view的位置。获取到具体的view后,对view进行操作,就能够实现局部刷新了。

关键代码:

 public void updateView(int itemIndex) {  
        //得到第一个可显示控件的位置,  
        int visiblePosition = mListView.getFirstVisiblePosition();  
        //只有当要更新的view在可见的位置时才更新,不可见时,跳过不更新  
        if (itemIndex - visiblePosition >= 0) {  
            //得到要更新的item的view  
            View view = mListView.getChildAt(itemIndex - visiblePosition);  
            //从view中取得holder  
            ViewHolder holder = (ViewHolder) view.getTag();  

            HashMap<String, Object> item = data.get(itemIndex);  
            //获取到具体的控件,
            holder.name = (TextView) view.findViewById(R.id.name);  
            holder.process = (ProcessBar) view.findViewById(R.id.process);  
            .......
            //对控件进行操作
            holder.process.setMax(item.get("max"));
            holder.process.setProgress(item.get("progress"));
            ......
     
        }         
    } 

时间: 2024-11-10 09:38:58

Android开发中ListView实现Item局部刷新的相关文章

Android开发之ListView实现Item局部刷新_Android

对于android中的ListView刷新机制,大多数的程序员都是很熟悉的,修改或者添加adapter中的数据源之后,然后调用notifyDataSetChanged()刷新ListView.在这种模式下,我们会在getView中,根据不同的数据源,让控件显示不同的内容.这种模式是最常见的刷新模式,当我们来回滑动ListView的时候,调用adapter的getView方法,然后listview对adapter返回的View进行绘制.这种模式下,View的显示内容或状态都记录在adapter里面

Android开发之ListView实现Item局部刷新

对于android中的ListView刷新机制,大多数的程序员都是很熟悉的,修改或者添加adapter中的数据源之后,然后调用notifyDataSetChanged()刷新ListView.在这种模式下,我们会在getView中,根据不同的数据源,让控件显示不同的内容.这种模式是最常见的刷新模式,当我们来回滑动ListView的时候,调用adapter的getView方法,然后listview对adapter返回的View进行绘制.这种模式下,View的显示内容或状态都记录在adapter里面

Android开发中Listview动态加载数据的方法示例

本文实例讲述了Android开发中Listview动态加载数据的方法.分享给大家供大家参考,具体如下: 最近在研究网络数据加载的问题,比如我有几百,甚至上千条数据,这些数据如果一次性全部加载到arraylist,然后再加载到Listview中.我们必然会去单独开线程来做,这样造成的结果就是会出现等待时间很长,用户体验非常不好.我的想法是动态加载数据,第一次加载十条,然后往下面滑动的时候再追加十条,再往下面滑动的时候再去追加,这样大大减少了用户等待的时间,同时给处理数据留下了时间.网上看到了这样一

android开发中listview添加图片

问题描述 android开发中listview添加图片 map1.put("image",R.drawable.jiantou); 我在listview中添加图像时,引用图像的地址,如上所示,但提示错误The method put(String, String) in the type HashMap is not applicable for the arguments (String, int) 但我看别人的代码都可以直接引用图像地址的,请大神帮忙解决一下,谢啦!! 解决方案 Ma

android开发中ListView与Adapter使用要点介绍_Android

1. Adapter.getView() public View getView(int position, View convertView , ViewGroup parent){...} 这个方法就是用来获得指定位置要显示的View.官网解释如下: Get a View that displays the data at the specified position in the data set. You can either create a View manually or infl

Android开发中ListView 和 ScrollView 冲突如何解决

ListView 与 ScrollView 同在一界面会导致ListView 显示变形,ListView只显示出了一个条目的高度,本文我们来谈谈如何解决Android应用中ListView 和 ScrollView 共生的问题. 一开始就想着用一个ScrollView把主要内容和评论区的ListView包起来,然后添加各个控件的内容即可,但是写出来之后发现ListView只显示出了一个条目的高度,并且不能滑动,网上搜了一下发现原因是ScrollView和ListView都是可滑动的,把它们放在一

Android开发中ListView显示不同样式的item实例方法

还是先看效果图吧 我们再使用listview时,大多时候listview的item大多时候都是一种样式,在很多app中也很常见,但有时候根据需求,可能数据的数量不一样,同个类型的数据显示的位置不同,亦或者有的item需要图片,有的不需要,但是这些又必须在同一个listview中显示,这时我们就需要在listview中显示多种样式的item,首先我们需要考虑的是如何将不同数量的数据装载到ArrayList<~>中呢,先看看下面的listViewItem,. package com.example

Android开发中ListView嵌套GridView问题详解

开发中,遇到一个问题,是ListView嵌套GridView,需要点击整个ListView的Item进行跳转.但是在点击GridView区域时无法进行页面的跳转.这是因为GridView获得了焦点.导致点击无法跳转. 解决方法就是: 1.在Item最外层加上 android:descendantFocusability="blocksDescendants" 2.在Adapter中添加 holder.mGridView.setClickable(false); holder.mGrid

ListView实现Item局部刷新

 对于ListView数据的刷新大家都知道,改变Adapter的数据源,然后调用Adapter的notifyDateSetChanged()方法即可. 但是博主在做公司项目的时候,有个下载模块,因为可能同时下载好几个数据,所 以用的listview展示所有正在下载的内容.因为下载进度要实时更新,所以要不停的调用notifyDateSetChanged刷新数据.这样会不 停的重新绘制整个listview的界面,性能开销非常大.而且如果每个item有图片的话,每个item的图片都需要重新加载,就算图