【问题标题】:Universal-Image-Loader: wrong Bitmaps are attached to ImageViewUniversal-Image-Loader:错误的位图附加到 ImageView
【发布时间】:2012-12-14 08:16:45
【问题描述】:

我一直在评估 NOSTRAUniversal-Image-Loader 库以异步下载图像并在 ListView 中显示它们。到目前为止,它工作正常,除了一个问题。

有时,当列表滚动时,内存缓存中的位图会附加到错误的ImageViews。滚动停止后,将附加正确的图像。这种情况非常罕见,我找不到 100% 的方法来重现它。上次发生这种情况时,我拍摄了video

这里是ArticleAdapter 代码,UIL 配置和bindView() 方法都可以在那里找到。

public class ArticleAdapter extends CursorAdapter {
    private LayoutInflater inflater;
    private ViewHolder holder;

    public ArticleAdapter(Context context, Cursor cursor, boolean autoRequery) {
        super(context, cursor, autoRequery);
        imageLoader = ImageLoader.getInstance();
        DisplayImageOptions options = new DisplayImageOptions.Builder()
                .showStubImage(R.drawable.download_progress_thumb)
                .cacheInMemory()
                .cacheOnDisc()
                .imageScaleType(ImageScaleType.IN_SAMPLE_POWER_OF_2)
                .build();
        ImageLoaderConfiguration configuration = new ImageLoaderConfiguration.Builder(context)
                .threadPriority(Thread.NORM_PRIORITY - 2)
                .threadPoolSize(4)
                .discCache(new UnlimitedDiscCache(Utils.getCacheDirectory(context)))
                .defaultDisplayImageOptions(options)
                .build();
        imageLoader.init(configuration);

        titleIndex = cursor.getColumnIndex(Articles.TITLE);
        descriptionIndex = cursor.getColumnIndex(Articles.DESCRIPTION);
        isUnreadIndex = cursor.getColumnIndex(Articles.IS_UNREAD);
        isNewIndex = cursor.getColumnIndex(Articles.IS_NEW);
        urlIndex = cursor.getColumnIndex(Articles.URL);
        hostIndex = cursor.getColumnIndex(Articles.HOST);
        timeIndex = cursor.getColumnIndex(Articles.PUBLISH_TIME);

        bkgUnreadArticle = context.getResources().getColor(R.color.list_bkg_unread_article);
        bkgReadArticle = context.getResources().getColor(R.color.list_bkg_read_article);
        textUnreadTitle = context.getResources().getColor(R.color.list_text_unread_title);
        textReadTitle = context.getResources().getColor(R.color.list_text_read_title);

        inflater = LayoutInflater.from(context);
    }

    @Override
    public void bindView(View view, Context context, Cursor cursor) {
        String date = Utils.format(cursor.getLong(timeIndex), Utils.DATE);
        holder = (ViewHolder) view.getTag();

        holder.titleView.setText(cursor.getString(titleIndex));
        holder.descriptionView.setText(date);

        int isNew = cursor.getInt(isNewIndex);
        if (isNew == 1)
            holder.isNewView.setVisibility(View.VISIBLE);
        else
            holder.isNewView.setVisibility(View.INVISIBLE);

        int isUnread = cursor.getInt(isUnreadIndex);
        if (isUnread == 1){
            holder.titleView.setTextColor(textUnreadTitle);
            holder.rowLayout.setBackgroundColor(bkgUnreadArticle);
        } else {
            holder.titleView.setTextColor(textReadTitle);
            holder.rowLayout.setBackgroundColor(bkgReadArticle);
        }

        String url = cursor.getString(urlIndex);
        String host = cursor.getString(hostIndex);
        if (host.equalsIgnoreCase(Consts.HOST_LENTA) || host.equalsIgnoreCase(Consts.HOST_REALTY)) {
            holder.thumbView.setVisibility(View.VISIBLE);
            imageLoader.displayImage(Utils.makeImageUrl(url, Utils.THUMBNAIL), holder.thumbView);
        } else 
            holder.thumbView.setVisibility(View.GONE);
    }

    @Override
    public View newView(Context context, Cursor cursor, ViewGroup parent) {
        View v = inflater.inflate(R.layout.articlelist_item, null);
        ViewHolder holder = new ViewHolder();
        holder.titleView = (TextView) v.findViewById(R.id.list_title);
        holder.descriptionView = (TextView) v.findViewById(R.id.list_description);
        holder.thumbView = (ImageView) v.findViewById(R.id.list_thumb);
        holder.isNewView = (TextView) v.findViewById(R.id.list_read_unread);
        holder.rowLayout = (LinearLayout) v.findViewById(R.id.list_row);

        v.setTag(holder);
        return v;
    }
}

我非常感谢您对此事的任何帮助。

【问题讨论】:

  • @samintechvalens 请不要加粗关键字,如果要突出代码相关的关键字,请使用反引号内联。
  • 你使用PauseOnScrollListener吗?
  • @NOSTRA 是的,我确实使用它。

标签: java android universal-image-loader


【解决方案1】:

对于 ListViews、GridViews 和其他在其适配器中被视图重用的列表您应该在 DisplayImageOptions 中调用 .resetViewBeforeLoading() 以防止这种影响。

还有文档说:

只用一次配置初始化 ImageLoader

你只做一次吗? Adapter 的构造函数不适合它。

UPD:抱歉,我的回答没有用。 .resetViewBeforeLoading() 无济于事,因为您使用的是 .showStubImage(...)。所以你应该有正确的 UIL 工作,但你没有。而且很奇怪。

【讨论】:

  • 是的,我刚刚做到了。将测试该应用几天,看看是否可以正常工作。
  • 不幸的是,.resetViewBeforeLoading() 没有帮助 - 今天又出现了问题。
  • 您似乎没有启动一次 ImageLoader。你确定你只在你的应用中的一个地方调用imageLoader.init(configuration);吗?
  • 是的,我只做了一次,在适配器的构造函数中。我应该在哪里做?
  • 在应用程序类中。查看示例项目。我也更新了我的答案。你的问题真的很奇怪。您能否描述更多细节:何时重现此错误?经过一些动作?经常?不断地?很少?安卓版? UIL 版本?
【解决方案2】:

我经常遇到这个问题,即使我只启动了一次 ImageLoader,我并没有只在我需要它时(在适配器中)才这样做,在我更改 Application 类中的 init() 部分之后它工作得很好。我什至不必使用restartViewOnLoading() 或setStubImage()。如果需要,这里是代码。

import android.content.Context;

import com.nostra13.universalimageloader.core.DisplayImageOptions;
import com.nostra13.universalimageloader.core.ImageLoader;
import com.nostra13.universalimageloader.core.ImageLoaderConfiguration;

public class Application extends android.app.Application {

    private static Context mContext;

    @Override
    public void onCreate() {
        super.onCreate();
        mContext = getApplicationContext();

        DisplayImageOptions imgOptions = new DisplayImageOptions.Builder()
            .cacheInMemory(true)
            .showImageOnLoading(R.drawable.default_picture)
            .build();
        ImageLoaderConfiguration imgConfig = new ImageLoaderConfiguration.Builder(mContext)
            .defaultDisplayImageOptions(imgOptions)
            .build();
        ImageLoader.getInstance().init(imgConfig);
    }

    public static Context getAppContext(){
        return mContext;
    }
}

编辑:您可以查看此对话here 以更深入地了解该问题。 基本上有3种解决方案

1) 在 dips 中为 ImageViews 设置 android:layout_width 和 android:layout_height 参数('wrap_content' 和 'match_parent' 是不可接受的)

2) ImageView 绘制完成后调用 ImageLoader(在 imageView.post(...) 中:

imageView.post(new Runnable() {
        @Override
        public void run() {
            imageLoader.displayImage(imageUri, imageView);
        }
     });

3) 通过不考虑实际视图大小的 ImageViewAware(而不是 ImageView):

相对于:

imageLoader.displayImage(imageUri, imageView);

执行以下操作:

ImageAware imageAware = new ImageViewAware(imageView, false)
imageLoader.displayImage(imageUri, imageAware);

【讨论】:

    【解决方案3】:

    看看如何设置Holders,因为我认为你在Adapter 中编写了错误的逻辑,这就是它重复视图的原因。

    还有Custom Cursor Adapter with HolderGet View & BindView讨论。

    【讨论】:

    • 恐怕不是这样的。只有图像有问题,项目上的其他所有内容(标题和日期)都正确显示。
    • 嗯..你试过SimpleImageLoadingListenerimageLoader.displayImage吗?因为它会给你一些通知,比如onLoadingCancelledonLoadingCompleteonLoadingStartedonLoadingFailed。您可以在此侦听器中执行其他更改。
    【解决方案4】:

    在你的代码中添加这一行 ::

    holder.thumbView.setTag(Utils.makeImageUrl(url, Utils.THUMBNAIL).get(position));
    imageLoader.displayImage(Utils.makeImageUrl(url, Utils.THUMBNAIL), view_holder.image);
    

    【讨论】:

      【解决方案5】:

      我有同样的问题并解决了它。这不是因为 Universal-Image-Loader 库。这是因为您在错误的逻辑中使用了 holder 来加载图像。

      尝试替换

          @Override
          public View newView(Context context, Cursor cursor, ViewGroup parent) {
              View v = inflater.inflate(R.layout.articlelist_item, null);
              ViewHolder holder = new ViewHolder();
              holder.titleView = (TextView) v.findViewById(R.id.list_title);
              holder.descriptionView = (TextView) v.findViewById(R.id.list_description);
              holder.thumbView = (ImageView) v.findViewById(R.id.list_thumb);
              holder.isNewView = (TextView) v.findViewById(R.id.list_read_unread);
              holder.rowLayout = (LinearLayout) v.findViewById(R.id.list_row);
      
              v.setTag(holder);
              return v;
          }
      

      @Override
          public View newView(Context context, Cursor cursor, ViewGroup parent) {
              View v = inflater.inflate(R.layout.articlelist_item, null);
              ViewHolder holder = new ViewHolder();
              holder.titleView = (TextView) v.findViewById(R.id.list_title);
              holder.descriptionView = (TextView) v.findViewById(R.id.list_description);
              ImageView thumbView = (ImageView) v.findViewById(R.id.list_thumb);
              imageLoader.displayImage("Your image URL", thumbView);
              holder.isNewView = (TextView) v.findViewById(R.id.list_read_unread);
              holder.rowLayout = (LinearLayout) v.findViewById(R.id.list_row);
      
              v.setTag(holder);
              return v;
          }
      

      记得在你的 bindView 函数中删除 imageloader

      【讨论】:

      • 如果对每个列表项都调用 newView(),那么持有者的概念就值得折腾了!所以这不是正确的方向。
      猜你喜欢
      • 2013-09-28
      • 1970-01-01
      • 2019-01-13
      • 1970-01-01
      • 2020-03-24
      • 2015-08-13
      • 2013-10-30
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多