10

我一直在尝试让缩略图与 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;
        }

    }

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

我仍然无法弄清楚要在滚动时让缩略图显示在正确的行上还要做些什么。

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

4

3 回答 3

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;
}
于 2012-07-28T19:53:34.333 回答
1

使用 AsyncTask.THREAD_POOL_EXECUTOR 最终会运行多个线程来获取缩略图。他们运行或完成并为视图设置图像的方式没有顺序。来回滚动时,您最终可能会在视图中看到错误的图像。

我测试了 AsyncTask.THREAD_POOL_EXECUTOR,它确实导致某些视图的图像错误。

于 2013-06-26T09:15:24.023 回答
0

您可以尝试将 ListView 从您的活动传递到您的适配器构造函数中(甚至可能进入您的异步任务,这取决于您希望如何实现它)。并使用 getFirstVisiblePosition() 和 getLastVisiblePosition() 与您的位置进行比较mPosition

于 2013-01-18T09:12:00.077 回答