1

我直接从 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

4

2 回答 2

0

它可能与控制受异步更新影响的列表的排序顺序有关。列表项大小的快速变化可能会混淆列表视图的呈现代码。一个建议是直接为每个列表项添加一个默认(可能是黑色)图像,该图像大小相同。然后随着真实图像的出现,只需替换黑色图像即可。


编辑:似乎这个问题是由 Android 回收 ViewItem/row 和异步任务造成的。有关更多详细信息和几​​个解决方案,请参阅此StackOverflow 问题。

于 2013-02-23T13:02:11.097 回答
0

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

但是,特定于 ListView 的行为揭示了我们当前实现的问题。实际上,出于内存效率的原因,ListView 会回收用户滚动时显示的视图。如果一个人抛出列表,一个给定的 ImageView 对象将被多次使用。每次显示时,ImageView 都会正确触发图像下载任务,最终会更改其图像。那么问题出在哪里?与大多数并行应用程序一样,关键问题在于顺序。在我们的例子中,不能保证下载任务会按照它们开始的顺序完成。结果是最终显示在列表中的图像可能来自上一个项目,只是碰巧下载的时间更长。

这是链接,他还提供了一个解决方案:

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

于 2013-04-30T04:56:53.320 回答