列表视图在翻转和滚动时显示错误的视图几秒钟[英] Listview showing wrong view for a few seconds while flinging and scrolling

本文是小编为大家收集整理的关于列表视图在翻转和滚动时显示错误的视图几秒钟的处理/解决方法,可以参考本文帮助大家快速定位并解决问题,中文翻译不准确的可切换到English标签页查看源文。

问题描述

系统似乎是回收视图,直到它在我的列表视图中加载正确的位置的视图,导致几秒钟的复制图像和文本.任何人都可以帮助吗?

@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;
}

几乎就像该位置被设置错误几秒钟.

推荐答案

您可以让视人持有对ASYNCTASK的引用.当convertView != null时,您可以在视图持有的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(...);
    ...
}

其他推荐答案

Android的Developer文档有一个很好的部分:

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

如上所述,您的ASYNCTASK正在对已经回收的视图保持了难以参考.

其他推荐答案

您可以通过适配器提供视图时将当前项图像视图设置为标准的加载图像,或者无法立即开始.这将始终"重置"图像,同时加载到异步任务上.这可能是保持回收意见性能效益的最佳方法.对于文本来说也是如此.

本文地址:https://www.itbaoku.cn/post/102785.html

问题描述

The system seems to be recycling views until it loads the correct position's view in my listview, resulting in duplicated images and text for a few seconds. Can anyone help?

@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;
}

It is almost as if the position is being set wrong for a few seconds.

推荐答案

You can let the ViewHolder hold a reference to the AsyncTask. When convertView != null, you can call cancel() on the AsyncTask held by the ViewHolder since you know the image it is loading will not be correct for this new row. In doInBackgrond() and onPostExecute(), first check if(!isCancelled()) before doing anything.

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(...);
    ...
}

其他推荐答案

Android's developer documentation has a great section on this:

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

This issue, as stated above, is that your AsyncTask is keeping a hard reference to a view that's already been recycled.

其他推荐答案

You could set the current items image view to a standard loading image or nothing right away when you provide the view via the adapter. This will always "reset" the image, while it is loaded on your async task. This is probably the best approach to keep the performance benefits of the recycled views. Same goes for the text.