为什么android ImageAdapter懒得加载图片?

时间:2014-02-16 14:25:48

标签: java android list listview android-asynctask

我有这个ImageAdapter for android的listView:

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    View view = null;
    RelativeLayout relativeLayout = null;
    Offer currentOffer = mOffersList.get(position);

    if (convertView == null) { // create a new view if no recycling
                                // available
        // Make up a new view
        LayoutInflater inflater = (LayoutInflater) mContext
                .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        view = inflater.inflate(R.layout.offer_list_item, null);
        relativeLayout = (RelativeLayout) view
                .findViewById(R.id.offerImage);

    } else {
        view = (View) convertView;
        relativeLayout = (RelativeLayout) view
                .findViewById(R.id.offerImage);
        setBackgroundDrawable(relativeLayout, null);

    }

    String imageUrl = "";
    imageUrl = currentOffer.getImageUrl().toString();

    Bitmap bitmap = imageCache.get(imageUrl);

    if (bitmap != null) {
        Drawable dr = new BitmapDrawable(mContext.getResources(), bitmap);
        setBackgroundDrawable(relativeLayout, dr);
    } else {
        if (!downloadingImageUrls.contains(imageUrl)) {
            downloadingImageUrls.add(imageUrl);
            new DownloadImageAsyncTask().execute(imageUrl);
        }
    }

    return view;
}

和此:

class DownloadImageAsyncTask extends AsyncTask<String, Void, Void> {
        @Override
        protected Void doInBackground(String... params) {
            String imageUrl = params[0];
            try {
                Bitmap bitmap = BitmapFactory
                        .decodeStream((InputStream) new URL(imageUrl)
                                .getContent());
                imageCache.put(imageUrl, bitmap);

            } catch (IOException e) {
                Log.e("DownloadImageAsyncTask", "Error reading bitmap" + e);
            }
            downloadingImageUrls.remove(imageUrl);
            return null;
        }

        @Override
        protected void onPostExecute(Void result) {
            notifyDataSetChanged();
        }
    }

为什么所有列表项都加载在一起?它不是异步但不是一个接一个。全部一起。

如何懒洋洋地加载它?

为什么这段代码更有效?

// better
public class DownloadImageAsyncTask2 extends
        AsyncTask<String, Void, Bitmap> {
    private final ImageView imageView;

    public DownloadImageAsyncTask2(ImageView imageView) {
        this.imageView = imageView;
    }

    @Override
    protected void onPreExecute() {
        Log.i("DownloadImageAsyncTask", "Starting image download task...");
    }

    @Override
    protected Bitmap doInBackground(String... params) {
        try {
            return BitmapFactory.decodeStream((InputStream) new URL(
                    params[0]).getContent());
        } catch (IOException e) {
            Log.e("DownloadImageAsyncTask", "Error reading bitmap" + e);
        }
        return null;
    }

    @Override
    protected void onPostExecute(Bitmap bitmap) {
        if (bitmap != null) {
            imageView.setImageBitmap(bitmap);
        }
    }
}

4 个答案:

答案 0 :(得分:2)

要回答您的初始问题,您编写的任何适配器都与其所称的完全相同;它是适配器。它允许您将数据转换为AdapterView中显示的视图。强迫所有观点“懒散地加载”是没有意义的,坦率地说,不应该出于某些原因这样做。

  1. 也许您已经预取了所有图片而且不需要延迟加载。也许他们甚至只是来自资源而根本不需要以特殊方式处理。
  2. 如何知道从哪里懒惰加载你的图像(数据库,内存映射,文件,网络资源,其他Android服务等)?在编写适配器时,这是你的工作。
  3. 你可能会认为Adapter子类具有loadLazily(Uri image, ImageView view)函数会很好。如果是这样,为什么不自己继承AbsAdapter并添加它或向AOSP提交补丁。但是,我怀疑你会发现即使像这样的函数也应该作为适配器的一部分包含在内。尽管在Android中依靠系统进行数据管理是多么正常,但以高效的方式管理数据确实是您的工作。

    要回答关于您提出的两种延迟加载方法的其他问题,不同之处在于第一种方法会导致AdapterView重新加载其所有视图,而在第二种方法中,您只是使您要加载的视图无效图片。

    我实际上并不同意第二种方法在整体上“更好”,因为每次更改配置或处理死亡并且需要重新加载视图时,您需要通过网络或文件系统进行新的调用加载你的图像。如果像在第一种方法中那样缓存它们,那么至少可以避免需要通过配置更改重新加载所有图像。如果您编写了一个单独的图像加载服务,该服务在其自己的进程中运行(不是我推荐的内容),您还可以避免第二种情况(您的:默认进程被杀死)。

    重点是,您负责加载图片,而不是Android。如果你想要它完成,你可以看看这些伟大的图像加载或Android的其他常规资源获取库:Local image caching solution for Android: Square Picasso vs Universal Image Loader。我之前亲自使用过Universal-Image-Loader,并承认它的效果与广告一致。但是,它会将您的所有图像缓存在外部存储上,这可能不适合您。

答案 1 :(得分:1)

listview可以为其onMeasure中的所有项调用getView(参见listView.java中的measureHeightOfChildren)。 因此,使用此getView,它会加载所有图像。

要延迟加载,您需要在其他位置加载图像:让视图在需要时(onDraw)向管理器(将以异步方式加载它们)询问图像。

notifyDataSetChanged()更新所有listview(意味着回收视图,调用getView ...),imageView.setImageBitmap只会更新ImageView,所以这是一个更好的主意。

答案 2 :(得分:0)

使用此图片加载器IMAGELOADER

答案 3 :(得分:0)

您可以使用此库https://github.com/thest1/LazyList。这很容易使用。