Listview在投掷和滚动时显示错误视图几秒钟

时间:2013-08-05 02:26:13

标签: android listview

系统似乎正在回收视图,直到它在我的列表视图中加载正确位置的视图,导致重复的图像和文本几秒钟。有人可以帮忙吗?

@Override
public View getView(final int position, View convertView, ViewGroup parent) {
    View v = convertView;
    Log.d("position",""+position);

    if(v==null){
        LayoutInflater inflater = LayoutInflater.from(mContext);
        v = inflater.inflate(R.layout.layout_appinfo, null);

        holder = new ViewHolder();
        holder.ivAppIcon = (ImageView)v.findViewById(R.id.ivIconApp);
        holder.tvAppName = (TextView)v.findViewById(R.id.tvNameApp);
        holder.progress = (ProgressBar)v.findViewById(R.id.progress_spinner);
        v.setTag(holder);
    } else {
        holder = (ViewHolder) v.getTag();
    }
    holder.ivAppIcon.setImageDrawable(null);
    holder.tvAppName.setText(null);
    holder.progress.setVisibility(View.VISIBLE);
    holder.ivAppIcon.setVisibility(View.GONE);

    // Using an AsyncTask to load the slow images in a background thread
    new AsyncTask<ViewHolder, Void, Drawable>() {
        private ViewHolder v;
        private ResolveInfo entry = (ResolveInfo) mListAppInfo.get(position);

        @Override
        protected Drawable doInBackground(ViewHolder... params) {
            v = params[0];
            return entry.loadIcon(mPackManager);
        }

        @Override
        protected void onPostExecute(Drawable result) {
            super.onPostExecute(result);
            // If this item hasn't been recycled already, hide the
            // progress and set and show the image
            v.progress.setVisibility(View.GONE);
            v.ivAppIcon.setVisibility(View.VISIBLE);
            v.ivAppIcon.setImageDrawable(result);
            v.tvAppName.setText(entry.loadLabel(mPackManager));
        }
    }.execute(holder);
    return v;
}

static class ViewHolder {
      TextView tvAppName;
      ImageView ivAppIcon;
      ProgressBar progress;
      //int position;
}

这几乎就好像位置设置错了几秒钟。

3 个答案:

答案 0 :(得分:6)

您可以让ViewHolder保存对AsyncTask的引用。当convertView != null时,您可以在ViewHolder持有的AsyncTask上调用cancel(),因为您知道它正在加载的图像对于这个新行不正确。在doInBackgrond()onPostExecute()中,首先检查if(!isCancelled())然后再做任何事情。

static class ViewHolder {
    TextView tvAppName;
    ImageView ivAppIcon;
    ProgressBar progress;
    AsyncTask task;
}

public View getView(int position, View convertView, ViewGroup parent) {
    ViewHolder holder;
    if (convertView == null) {
        /* inflate new view, make new ViewHolder, etc. */
        ...
    } else {
        holder = (ViewHolder) convertView.getTag();
        holder.task.cancel();
    }

    // always make a new AsyncTask, they cannot be reused
    holder.task = new AsyncTask ...
    holder.execute(...);
    ...
}

答案 1 :(得分:2)

Android的开发者文档有一个很好的部分:

http://developer.android.com/training/displaying-bitmaps/process-bitmap.html

如上所述,这个问题是您的AsyncTask对已经被回收的视图保持了硬性引用。

答案 2 :(得分:0)

当您通过适配器提供视图时,可以将当前项目图像视图设置为标准加载图像,或立即设置任何内容。这将始终“重置”图像,同时它将加载到您的异步任务上。这可能是保持循环视图的性能优势的最佳方法。同样适用于文本。