使用AsyncTask在ListView中混杂使用图像

时间:2013-02-23 12:25:07

标签: android performance bitmap android-asynctask

我直接从mp3上加载图片,并在我的应用程序中将它们与歌曲标题一起显示。为了平滑过程我使用AsyncTask并在后台加载图像。如果我慢慢滚动,图像会以正确的顺序显示。但是,如果我快速向上和向下滚动,则图像会混乱2-3秒(如显示的顺序不正确)。 2-3秒后,订单再次变为正常。我怎么能避免这个?这是我的代码:

public class TestAcitivity extends SherlockListActivity  {
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        ActionBar ab = getSupportActionBar();
        Uri sourceUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
        String [] proj = {MediaStore.Audio.Media._ID,MediaStore.Audio.Media.TITLE,MediaStore.Audio.Media.ALBUM_ID};
        CursorLoader cursorLoader = new CursorLoader(this, sourceUri,proj,
                                                        null, null, MediaStore.Audio.Media.TITLE);
        Cursor cursor = cursorLoader.loadInBackground();
        ListView lv = getListView();//(ListView)this.findViewById(R.id.listview);
        lv.setAdapter(new MyAdapter(this, cursor, CursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER));
    }
}
class MyAdapter extends CursorAdapter {

    private LayoutInflater mLayoutInflater;
    @SuppressWarnings("unused")
    private Context mContext;

    public MyAdapter(Context context, Cursor c, int flags) {
        super(context, c, flags);
        mContext = context;
        mLayoutInflater = LayoutInflater.from(context);
    }
    public void bindView(View view, Context context, Cursor cursor) {
        String title = cursor.getString(cursor.getColumnIndex(MediaStore.MediaColumns.TITLE));
        String album_id = cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Media.ALBUM_ID));
        TextView text = (TextView)view.findViewById(R.id.txtTitle);
        text.setText(title);
        if(Long.valueOf(album_id)>0)
        {
            Uri sArtworkUri = Uri.parse("content://media/external/audio/albumart");
            Uri uri = ContentUris.withAppendedId(sArtworkUri, Integer.valueOf(album_id));
            new MyImageLoader(context,view).execute(uri);
        }
    }

    @Override
    public View newView(Context context, Cursor cursor, ViewGroup parent) {
        View v = mLayoutInflater.inflate(R.layout.row, parent, false);
        //bindView(v, context, cursor);
        return v;
    }
    private class MyImageLoader extends AsyncTask<Uri, Void, Bitmap>{
        Context context;
        View view;
        MyImageLoader(Context context,View view){
            this.context = context;
            this.view = view;
        }
        @Override
        protected Bitmap doInBackground(Uri... uri) {

            ContentResolver res = context.getContentResolver();
            InputStream in = null;
            try {
                in = res.openInputStream(uri[0]);
            } 
            catch (FileNotFoundException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            Bitmap artwork = BitmapFactory.decodeStream(in);

            return artwork;

        }
        protected void onPostExecute(Bitmap bmp){
            ImageView iv = (ImageView)view.findViewById(R.id.imgIcon);
            if(bmp!=null)
                iv.setImageBitmap(Bitmap.createScaledBitmap(bmp, 100, 100, false));
        }
    }
}

我正在使用自定义CursorAdapter加载AsyncTask中的位图。

2 个答案:

答案 0 :(得分:0)

它可能与控制受异步更新影响的列表的排序顺序有关。它可能是列表项大小的快速变化,使列表视图的呈现代码混乱。一个建议是将默认(可能是黑色)图像直接添加到相同大小的每个列表项。然后当真实图像进来时,只需更换黑色图像。


编辑:似乎这个问题是由Android回收ViewItem /行引起的,而且这个问题与异步任务相混淆。有关更多详细信息和一些解决方案,请参阅此StackOverflow question

答案 1 :(得分:0)

Hack_on是正确的。其中一位Andorid工程师在博客中讨论了这个问题:

  

但是,特定于ListView的行为会显示我们的问题   目前的实施。的确,出于内存效率的原因,   ListView回收用户滚动时显示的视图。   如果一个人翻转列表,则会使用很多给定的ImageView对象   倍。每次显示时,ImageView都会正确触发   图像下载任务,最终将改变其图像。那么在哪里   是问题吗?与大多数并行应用程序一样,关键问题是   在订购中。在我们的例子中,不保证下载   任务将按照启动顺序完成。结果   是最终显示在列表中的图像可能来自a   上一个项目,它恰好花了更长的时间下载。   如果您下载的图像被绑定一次,那么这不是问题   所有给予ImageViews,但让我们解决它的常见情况   它们用在列表中。

这是链接,他也提供了解决方案:

http://android-developers.blogspot.com/2010/07/multithreading-for-performance.html