ListView中的ImageViews不会显示

时间:2013-04-16 14:39:11

标签: android listview caching android-asynctask android-imageview

我有使用EventAdapter的ListView。

public class EventAdapter extends BaseAdapter {
...
public View getView(int position, View view, ViewGroup parent) {
     ...
     cache.imgIcon.setImageDrawable(ImgCache.setImg(url, progressBar));
     ...
}

ImgCache用于缓存图像的类。

public class ImgCache {
    public static HashMap<String, Drawable> imgCache;

    // get img from cache if exist, or download and put in cache
    public static Drawable setImg(final String link, final ProgressBar progressBar) {
        final Drawable[] image = {null};
        if (imgCache.containsKey(link)) {
            image[0] = imgCache.get(link);
            progressBar.setVisibility(View.INVISIBLE);
        } else {
            new AsyncTask<Void, Void, Drawable>() {
                @Override
                protected Drawable doInBackground(Void... params) {
                    URL url = null;
                    try {
                        url = new URL(link);
                        URLConnection connection = url.openConnection();
                        image[0] = Drawable.createFromStream(connection.getInputStream(), "src");
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                    imgCache.put(link, image[0]);
                    return image[0];
                }

                @Override
                protected void onPostExecute(Drawable result) {
                    progressBar.setVisibility(View.INVISIBLE);
                }
            }.execute();
        }
        return image[0];
    }
}

问题是什么?

Activity打开ListView后,所有图片都开始加载。但是在加载完成后它们不显示。看起来像是:

enter image description here

然后我尝试向下滚动2个项目然后返回上一个位置。在这个操作后,我可以看到2个带有图像的上部项目。当我滚动到它们时,所有图像也都可见。

enter image description here

3 个答案:

答案 0 :(得分:2)

根据您的问题,您似乎需要在下载图像后刷新ListView(因为当您滚动它们时会出现):

adapter.notifyDataSetChanged();

答案 1 :(得分:2)

AsyncTask是异步的,因此您应用的流程为:

需要显示ListView项目 - &gt;为List项调用Adapter.getView(...) - &gt;如果图像不在缓存中,则执行AsyncTask并返回(不等待结果) 因此,当您向下滚动并向上滚动时,将再次调用Adapter.get(...)方法,但是这次图像位于缓存中,因此它返回显示的Drawable对象

解决此问题的一种方法是从AsyncTask回调适配器,一旦检索到适配器调用notifyDataSetChanged,就会更新映像,直接设置特定的Drawable或类似的东西(显示同时加载gif图像?)

或者

调用AsyncTask get(long timeout, TimeUnit unit)方法,该方法将阻止man线程并等待AsyncTask完成。完成后,它将返回结果(在这种情况下你的Drawable)。这将导致主UI线程在获取图像时挂起,因此不是最佳方式。

答案 2 :(得分:1)

问题是你的视图加载并填充你的列表OnCreate,但那时你的Async任务还没有返回你的列表所以当getView调用你的缓存时它是空的,因为当你滚动它时调用android View Recycling调用getView再次,这次你的缓存已被填充。

我建议您使用onPostExecute在ListView适配器上调用NotifyDataSetChanged,这会在您拥有图片后强制重绘。