Images jumble up in ListView using AsyncTask

雨燕双飞 提交于 2019-12-24 15:34:37

问题


I am loading images directly from mp3's and displaying them along with song title in my app. To smoothen the process I am using an AsyncTask and loading the images in background. If i scroll slowly the images appear in correct order with song. However , if I scroll up and down fast , then the images jumble up for 2-3 seconds (as in appear in an incorrect order). After 2-3 seconds the order again becomes normal. How can I avoid this ? Here is my code :

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));
        }
    }
}

I am using a custom CursorAdapter with loading bitmaps in AsyncTask.


回答1:


It could be related to what is controlling the sort-order of the list being affected by the asynchronous updates. It could be rapid changes in size of the list items confusing the rendering code for the list view. One suggestion is to add a default (possibly black) image to each list item straight off that is the same size. Then as the real images come in, just replace the black ones.


Edit: It seems that this problem is caused by Android recycling the ViewItem/row and that confusing things with an asynchronous task. See this StackOverflow question for more detail and a couple of solutions.




回答2:


Hack_on is correct. One of the Andorid engineers discusses this problem in a blog bost:

However, a ListView-specific behavior reveals a problem with our current implementation. Indeed, for memory efficiency reasons, ListView recycles the views that are displayed when the user scrolls. If one flings the list, a given ImageView object will be used many times. Each time it is displayed the ImageView correctly triggers an image download task, which will eventually change its image. So where is the problem? As with most parallel applications, the key issue is in the ordering. In our case, there's no guarantee that the download tasks will finish in the order in which they were started. The result is that the image finally displayed in the list may come from a previous item, which simply happened to have taken longer to download. This is not an issue if the images you download are bound once and for all to given ImageViews, but let's fix it for the common case where they are used in a list.

Here's the link, where he also offers a solution:

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



来源:https://stackoverflow.com/questions/15040505/images-jumble-up-in-listview-using-asynctask

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!