来自url的图像使用自定义光标适配器闪烁

时间:2016-07-29 18:36:14

标签: android listview android-asynctask android-adapter

我正在查询SQLite数据库并将数据放入List View。其中一个数据库行包含一个图像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);
    }
}

1 个答案:

答案 0 :(得分:1)

可能发生的事情是:

  • 您获得了一张图片的网址,并将AsyncTask排队以下载ImageView

  • 您滚动并且ImageView已被回收

  • 这次ImageView获取本地网址,因此您可以立即执行此操作

  • 之前排队的AsyncTask完成并在您刚放入的图片上加载一张现在无关的图片

清除此问题的关键是确保在ImageView被回收后取消任务。一种方法是在AsyncTask的标记中引用ImageView。当您获得回收的ImageView时,检查标记并查看是否有正在进行的任务,并在开始新任务之前将其取消。

你应该在Android开发者博客上查看这篇文章,它将更多地解释这个问题以及如何解决它:

Multithreading For Performance | Android Developers Blog

我认为这篇文章是在AsyncTask被改为在并行线程中运行时写回来的,因为它们讨论的是无序完成的任务。它们已经恢复到串行执行,因此我不认为该部分已经适用,但概念类似,因为您立即加载本地图像就像执行乱序的任务一样。

我会考虑另外两件事:

  • getView中,请务必先致电imageView.setImageBitmap(null)以清除回收的ImageView中的剩余图片。我喜欢使用一个非常中性的灰色位图来表示“图像加载”状态。

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