【问题标题】:Images from url flickering with custom cursor adapter来自 url 的图像使用自定义光标适配器闪烁
【发布时间】:2016-07-29 18:36:13
【问题描述】:

我正在查询 SQLite 数据库并将数据放入列表视图中。其中一个数据库行包含一个图像 Url 字段(也可以是一个 Uri)。

图像已按应有的方式加载,但当我滚动列表时,所有图像都开始闪烁,有些图像正在改变位置或显示在不同的位置。

我已经明白这种行为正在发生,因为列表视图在滚动时重用了行,但我不知道如何解决这种行为。我也不能在这个项目中使用像 Picasso 这样的外部库。

这是我的适配器代码:

    public class FilmsListCustomAdapter extends CursorAdapter {

    private LayoutInflater cursorInflater;

    public FilmsListCustomAdapter(Context context, Cursor c, int flags) {
        super(context, c, flags);
        cursorInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    }

    @Override
    public void bindView(View view, Context context, Cursor cursor) {
        TextView filmTitle = (TextView) view.findViewById(R.id.filmListTitle);
        TextView filmScore = (TextView) view.findViewById(R.id.filmListScore);
        ImageView filmImage = (ImageView)view.findViewById(R.id.filmListPoster);
        ImageView filmSeen = (ImageView)view.findViewById(R.id.filmListSeen);

        String title = cursor.getString( cursor.getColumnIndex("title") );
        String score = cursor.getString(cursor.getColumnIndex("score"));
        String url = cursor.getString( cursor.getColumnIndex("url") );
        int seen = cursor.getInt( cursor.getColumnIndex("seen") );

        if(Patterns.WEB_URL.matcher(url).matches()){
            LoadImage loadImage = new LoadImage(context,filmImage);
            loadImage.execute(url);
        }
        else{
            Bitmap bmp = BitmapFactory.decodeFile(url);
            CamImage camImage = new CamImage(context,Uri.parse(url));
            Bitmap rotetedIm = camImage.rotateCamImage(bmp,url);
            if(rotetedIm!=null){filmImage.setImageBitmap(Bitmap.createScaledBitmap(rotetedIm, 850, rotetedIm.getHeight(), false));}
            else{filmImage.setImageResource(R.drawable.no_poster);}
        }

        GlobalMethods methods = new GlobalMethods(context);
        filmTitle.setTypeface(methods.getWalkFont());
        filmTitle.setText(title);
        filmScore.setText(score);
        if(seen==1){filmSeen.setImageResource(R.drawable.eye);}
        else{filmSeen.setImageResource(0);}
    }

    @Override
    public View newView(Context context, Cursor cursor, ViewGroup viewGroup) {
        return cursorInflater.inflate(R.layout.film_row, viewGroup, false);
    }
}

【问题讨论】:

  • 我不明白你为什么不想使用毕加索图书馆。使用 Picasso 或 Glide 库显示具有存储图像功能的图像,因此无需在列表视图中下载。这是 Picasso 的链接:square.github.io/picasso 和 Glide 的链接:github.com/bumptech/glide
  • 不是我不想。这是一个学校项目,他们要求我不要使用外部库。

标签: android listview android-asynctask android-adapter


【解决方案1】:

可能发生的事情是这样的:

  • 您获得一个图片的网址并排队 AsyncTask 以下载它以获取 ImageView

  • 您滚动,ImageView 被回收

  • 这一次ImageView 获得了一个本地 URL,所以你立即这样做

  • 先前排队的AsyncTask 完成并在您刚刚放入的图像上加载一个现在不相关的图像

清除此问题的关键是确保在回收ImageView 后取消任务。您可以这样做的一种方法是将AsyncTask 的引用放在ImageView 的标记中。当你得到一个回收的ImageView时,你检查标签,看看是否有一个任务正在进行中,然后在你开始一个新任务之前取消它。

您应该查看 Android 开发者博客上的这篇文章,它将详细解释该问题以及如何解决它:

Multithreading For Performance | Android Developers Blog

我认为这篇文章是在将AsyncTasks 更改为在并行线程中运行时写回的,因为他们谈论的是任务无序完成。他们已经恢复到串行执行,所以我认为这部分不再适用,但是这个概念是相似的,因为你立即加载本地图像就像任务执行乱序一样。

我会考虑另外两件事:

  • getView 中,始终首先调用imageView.setImageBitmap(null) 以清除回收的ImageView 中的任何剩余图像。我喜欢用一个非常中性的灰色位图来初始化ImageViews,它表示“图像加载”状态。

  • 使用 AsyncTask 解码本地文件以及检索 Web 文件。我敢打赌,当你这样做时,你的列表滚动看起来会更流畅。

【讨论】:

    猜你喜欢
    • 2014-04-24
    • 2011-09-08
    • 1970-01-01
    • 1970-01-01
    • 2023-04-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多