Android ListView使用AsyncTask更新图像缩略图导致视图回收

Dak*_*ksh 10 android listview thumbnails recycle android-asynctask

我一直在尝试使用缩略图来处理ListView中的图像文件的AsyncTask.我一直遇到行回收的常见问题,因此滚动缩略图被分配给错误的行.我已经尝试将标签添加到ImageView,然后在AsyncTask中的onPostExecute()中确认标签,但是在我的尝试中却没有成功.有人请帮忙!

自定义适配器如下:

public class MySimpleAdapter extends SimpleAdapter {

        public MySimpleAdapter(Context context,
                List<? extends Map<String, ?>> data, int resource,
                String[] from, int[] to) {
            super(context, data, resource, from, to);
            // TODO Auto-generated constructor stub
        }

        public View getView(int position, View convertView, ViewGroup parent) {
            final View v = super.getView(position, convertView, parent);
            thumbnail = (ImageView) v.findViewById(R.id.thumbnail);
            checker = (CheckBox) v.findViewById(R.id.checkBox);
            filenametext = (TextView) v.findViewById(R.id.text1);
            String pathtoimage = startLocation.concat("/"
                    + filenametext.getText().toString());
            desctext = (TextView) v.findViewById(R.id.text2);
            String temp = desctext.getText().toString();
            if (temp.equals("Directory") == true) {
                checker.setEnabled(false);
                switch (theme) {
                case 0:
                    thumbnail.setImageResource(R.drawable.folder_light);
                    break;
                case 1:
                    thumbnail.setImageResource(R.drawable.folder_dark);
                    break;
                }

            } else {
                checker.setEnabled(true);
                if (filenametext.getText().toString().endsWith(".jpg")
                        || filenametext.getText().toString().endsWith(".png")
                        || filenametext.getText().toString().endsWith(".bmp")) {
                    Boolean hashmapfound = false;
                    for (HashMap.Entry<String, Bitmap> entry : thumbnaillist
                            .entrySet()) {
                        String key = entry.getKey();
                        if (key.equals(filenametext.getText().toString())) {
                            Log.d(TAG, "HashMapKey Found!");
                            thumbnail.setImageBitmap(entry.getValue());
                            hashmapfound = true;
                        }
                    }
                    if (!hashmapfound) {
                        Log.d(TAG, "NO HashMapKey Found! Adding to HashMap!");
                        switch (theme) {
                        case 0:
                            thumbnail
                                    .setImageResource(R.drawable.unknown_image_light);
                            break;
                        case 1:
                            thumbnail
                                    .setImageResource(R.drawable.unknown_image_dark);
                            break;
                        }
                        thumbnail.setTag((filenametext.getText().toString()));
                        new GetBitMaps(thumbnail).execute(pathtoimage,
                                filenametext.getText().toString());
                    }

                } else {
                    switch (theme) {
                    case 0:
                        thumbnail.setImageResource(R.drawable.file_light);
                        break;
                    case 1:
                        thumbnail.setImageResource(R.drawable.file_dark);
                        break;
                    }
                }
            }
            return v;
        }

    }
Run Code Online (Sandbox Code Playgroud)

AsyncTask如下:

class GetBitMaps extends AsyncTask<String, Void, Bitmap> {

    private ImageView thumbnail;
    private String imageName;

    public GetBitMaps(ImageView thumb) {
        // TODO Auto-generated constructor stub
        thumbnail = thumb;
    }

    @Override
    protected Bitmap doInBackground(String... pathtoimage) {
        Bitmap bmp = createThumbnail(pathtoimage[0]);
        thumbnaillist.put(pathtoimage[1], bmp);
        imageName = pathtoimage[1];
        return bmp;
    }

    @Override
    protected void onPostExecute(Bitmap bmp) {

        if (((String) thumbnail.getTag()).equals(imageName)) {
            thumbnail.setImageBitmap(bmp);
        }
    }

    private Bitmap createThumbnail(String filepath) {
        Bitmap bmp = BitmapFactory.decodeFile(filepath);
        int w = bmp.getWidth();
        int h = bmp.getHeight();
        if (w > h) {
            w = 80;
            h = 40;
        } else if (w < h) {
            w = 40;
            h = 80;
        }
        bmp = Bitmap.createScaledBitmap(bmp, w, h, true);

        return bmp;
    }
}
Run Code Online (Sandbox Code Playgroud)

我仍然无法弄清楚还有什么可以让缩略图显示在滚动的正确行上.

请注意:滚动远离受影响的行并向下滚动后,一切正常,但滚动问题不会消失!

Jef*_*rod 20

来自这篇博文:

您要做的是在一个单独的线程中异步运行所有每行IO或任何繁重的CPU绑定例程.这里的诀窍是这样做,仍然符合ListView的回收行为.例如,如果运行AsyncTask以在适配器的getView()中加载配置文件图片,则在AsyncTask完成之前,您正在加载图像的视图可能会被回收到另一个位置.因此,您需要一种机制来了解一旦完成异步操作后视图是否还没有被回收.

实现此目的的一种简单方法是将一些信息附加到视图,以识别与其关联的行.然后,您可以在异步操作完成时检查视图的目标行是否仍然相同.有很多方法可以实现这一目标.这里只是一个简单的草图,你可以做到这一点:

public View getView(int position, View convertView,
        ViewGroup parent) {
    ViewHolder holder;

    ...

    holder.position = position;

    new ThumbnailTask(position, holder)
            .executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, null);

    return convertView;
}

private static class ThumbnailTask extends AsyncTask {
    private int mPosition;
    private ViewHolder mHolder;

    public ThumbnailTask(int position, ViewHolder holder) {
        mPosition = position;
        mHolder = holder;
    }

    @Override
    protected Cursor doInBackground(Void... arg0) {
        // Download bitmap here
    }

    @Override
    protected void onPostExecute(Bitmap bitmap) {
        if (mHolder.position == mPosition) {
            mHolder.thumbnail.setImageBitmap(bitmap);
        }
    }
}

private static class ViewHolder {
    public ImageView thumbnail;
    public int position;
}
Run Code Online (Sandbox Code Playgroud)

  • 光标是什么?什么回报? (2认同)