Android開發中ListView實現Item局部重新整理

來源:互聯網
上載者:User

對於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"));
            ......
     
        }         
    } 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.