2

我在列表的ImageView每一行都显示一个列表。

为此,我使用另一个 AsyncTask 从网络下载图像,Drawable.createFromStream 并将它们存储为Drawable,在ArrayList其中我传递给扩展 BaseAdapter 类的适配器类。

但是这些图像是用高分辨率相机拍摄的,因此尺寸可能非常大。我得到了OutOfMemory错误。

所以我的问题:

  1. 将图像存储为可绘制或位图或任何其他格式更有效的是什么?

  2. 通过将所有图像存储在内存中(在数组列表中),我做得对吗?即我在想,一旦我得到一张图像,我会在 ImageView 上显示它,而不是存储在 ArrayList 中。

  3. 有什么办法吗,我可以在下载后压缩图像,这样它们会占用更少的内存空间。

我的总代码在这里

4

3 回答 3

1

Android 文档提供了一个很好的示例,展示了如何在您的 android 应用程序中处理位图。该示例使用磁盘和内存缓存并在后台加载图像。通过这样做,主 UI 线程不会因加载图像而减慢速度。

有效加载位图

在示例中,图像是从 picasa 加载的。但是,修改该示例很容易,以便使用本地存储的图片。您只需编写自己的 ImageLoader,从“ImageResizer”扩展而来:

public class ImageLoader extends ImageResizer {
    public ImageLoader(Context context, int imageWidth, int imageHeight) {
        super(context, imageWidth, imageHeight);
    }
    public ImageLoader(Context context, int imageSize) {
        super(context, imageSize);
    }
    @Override
    protected Bitmap processBitmap(Object data) {
        return decodeSampledBitmapFromFile((String)data, imageWidth, imageHeight);
    }
}

但是要直接回答您的问题:可以将图像加载为位图。但是您必须使用缓存和弱引用,以便可以对图像进行垃圾收集,以防它们在屏幕上不可见。缓存它们并使用后台任务进行加载可以实现流畅的 UI。

于 2013-01-11T08:58:48.117 回答
1

有很好的图书馆调用AQuery。您可以使用它,只需编写 2 行代码即可轻松获取内存和文件缓存等所有内容。所以你甚至不需要准备一个drawable,你可以直接从Adapter.getView()回调中调用它。

AQuery aq = new AQuery(rowView);
aq.id(R.id.image).image(url, false, true);

希望对你有帮助!

来自 AQuery 文档:

下采样(处理大图像) 我们正在从网络加载一个大图像,但我们只需要图像大于 200 像素宽。传入 200 的目标宽度将对图像进行下采样以节省内存。Aquery 只会以 2 (2,4,8...) 的幂进行下采样以获得良好的图像质量和效率。生成的图像宽度将在 200 之间和 399 像素

String imageUrl = "http://farm6.static.flickr.com/5035/5802797131_a729dac808_b.jpg";
aq.id(R.id.image1).image(imageUrl, true, true, 200, 0);

于 2013-01-11T07:51:20.763 回答
1
  1. 我没有看到将高密度图像存储到内存中的任何效率 - 完全不建议将大量图像作为位图存储在内存中(对你有好处,你有一个好的设备;))
  2. 见第 1 页
  3. 尝试缩小图像以适应设备的需求——但这并不是一项简单的工作。另请参阅View.setTag(Object tag)

适配器

public class MyImageListAdapter extends BaseAdapter implements ImageLoadingNotifier {

private LayoutInflater inflater = null;

public MyImageListAdapter() {
    inflater = LayoutInflater)HomeActivity.this.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}

public int getCount() {
    return listImageInfo.size();
}

public Object getItem(int position) {
    return listImageInfo.get(position);
}

public long getItemId(int position) {
    return position;
}

public View getView(int position, View convertView, ViewGroup parent) {
    View vi = convertView;
    if (convertView == null) {
        vi = inflater.inflate(R.layout.list_row, null);
    }

    TextView tvName = (TextView) vi.findViewById(R.id.tv_name);
    TextView tvTime = (TextView) vi.findViewById(R.id.tv_time);
    ImageView image = (ImageView) vi.findViewById(R.id.iv_image);
    final Button btnDelete = (Button) vi.findViewById(R.id.btn_delete);


    image.setImageDrawable(R.drawable.default_placeholder);//set default place-holder
    new GetDrawableFromUrl(listImageInfo.get(position), vi).execute();

    tvName.setText("Name: " + listImageInfo.get(position).getImage_name());
    tvTime.setText("Date: " + listImageInfo.get(position).getDate_created());

    btnDelete.setOnClickListener(new OnClickListener() {
        public void onClick(View v) {
            final int position = listView.getPositionForView((View) v.getParent());
            positionOgBtnToDelete = position;
            Log.v("delete btn clicked", "delete btn no: " + position);
            Toast.makeText(HomeActivity.this, "Btn delete position: " + position, Toast.LENGTH_LONG).show();
            showAlertToConfirmDelete();
        }
    });
    return vi;
}

}

异步任务GetDrawableFromUrl

public class GetDrawableFromUrl extends AsyncTask<Void, Void, Drawable> {
public ImageInfo imageInfoObj;
private ImageView view;


GetDrawableFromUrl(ImageInfo imageInfo, ImageView view) {
    imageInfoObj = imageInfo;
    this.view = view;
}

@Override
protected Drawable doInBackground(Void... params) {
    try {
        return Drawable.createFromStream(((java.io.InputStream) new java.net.URL(imageInfoObj.getImageUrl()).getContent()), "src_name");
    } catch (Exception e) {
        e.printStackTrace();
    }
    return null;
}

protected void onPostExecute(Drawable drawable) {
    if (drawable != null) {
        //imageInfoObj.setImage(drawable);
        this.view.setImageDrawable(drawable);
        //listImageInfo.add(imageInfoObj); //this one is called when the json is parsed
        showImagesInList(); //don't know what it does (??)
    }
}

}

JSON解析

JSONArray jsonArray = jsonObj.getJSONArray("result");
            for (int i = 0; i < jsonArray.length(); i++) {
                JSONObject jsonObjInner = jsonArray.getJSONObject(i);

                ImageInfo imageInfo = new ImageInfo();
                imageInfo.setImageUrl("http://www.dvimaytech.com/markphoto/" + jsonObjInner.getString("image"));

                //new GetDrawableFromUrl(imageInfo).execute(); //don't needed here

                imageInfo.setEmail(jsonObjInner.getString("emailid"));
                imageInfo.setImage_id(jsonObjInner.getString("image_id"));
                imageInfo.setImage_name(jsonObjInner.getString("image_name"));
                imageInfo.setAmount(jsonObjInner.getString("amount"));
                imageInfo.setImage_description(jsonObjInner.getString("image_description"));
                imageInfo.setDate_created(jsonObjInner.getString("date_created"));

                listImageInfo.add(imageInfo);
            }

而且,使用任何类型的List图像都变得不必要了:)

解析 json 对象时,不用启动异步任务(GetDrawableFromUrl),可以在getView(...)方法中启动任务。这样,您将不会被限制将可绘制对象存储到 中ArrayList,因为您将ImageView在图像下载后进行修改。并且,默认情况下,您可以放置​​一个占位符,直到下载图像(或者如果有一些网络错误)。

getView这样,只有在为该特定项目调用该方法时,图像才会开始下载。

最重要的是,来自 的每个视图ListView都将保留对其特定可绘制对象的引用(使用vi.setTag(image).

如果这有帮助,你知道该怎么做;)

于 2013-01-11T08:52:07.813 回答