带有位图的CustomListView - OutOfMemory错误

时间:2012-07-23 16:11:36

标签: android bitmap android-listview android-arrayadapter out-of-memory

我对Android开发相对较新,我正在尝试使用ImageView和TextView创建自定义ListView。我正在将URL转换为位图图像,然后尝试在imageView中显示图像。但是我收到错误,我的应用程序立即崩溃。能够在我的imageView中显示一个drawable,我做了一些修改,并试图显示一个位图,然后我的应用程序崩溃了。任何帮助将不胜感激。这是我的3个班级:

编辑我使用asynctask在单独的线程上获取位图图像,现在我的应用程序不再崩溃了。但是当我开始活动时它不会显示列表视图。这是我更新的代码。

编辑我再次更改了代码,我只在异步任务的execute方法中传递了一个imageView。我现在能够在列表视图中看到该文本,但我看不到图像。这是我编辑的代码。

编辑我使用调试器找出未显示位图的原因,我发现我的位图变量为空。这是因为我没有添加互联网权限。添加权限后,我的应用程序开始在给定行崩溃:

 b = BitmapFactory.decodeStream(image_url.openConnection() .getInputStream());

由于OutofMemory错误,我收到了RuntimeException。我不知道如何解决这个问题。我将不胜感激任何帮助。谢谢!

这是我的Loadimage AsyncTask类:

 public class LoadImage extends AsyncTask<String, Integer, Bitmap>{

    Context callingContext = null;
    Bitmap b = null;

    ImageView view;

    public LoadImage(ImageView view){

        this.view = view;
    }

    @Override
    protected Bitmap doInBackground(String... arg0) {
        // TODO Auto-generated method stub
        String p_url = "http://java.sogeti.nl/JavaBlog/wp-content/uploads/2009/04/android_icon_256.png";

        Bitmap b = null;
        try {
            URL image_url = new URL(p_url);
            b = BitmapFactory.decodeStream(image_url.openConnection() .getInputStream());

        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return b;
    }



    @Override
    protected void onPostExecute(Bitmap result) {
        // TODO Auto-generated method stub
        super.onPostExecute(result);
        view.setImageBitmap(result);

    }   
}

1 个答案:

答案 0 :(得分:2)

您的代码崩溃是因为您在严格模式下从UI线程上的服务器上加载图像文件。这通常被认为是不好的做法,因为如果图片需要很长时间才能下载,那么您的应用似乎已被锁定。

严格模式正在强制崩溃(抛出异常)。如果您禁用严格模式,它应该让您的应用程序正常工作。但是,在UI线程上执行网络I / O的问题仍然存在。

更好的长期解决方案是使用像AsyncTask这样的东西。这将在不同的线程上加载您的图像,从而保持您的应用程序响应。 AsyncTask的文档有一个下载图片的简单示例,this helper page有更多信息。

举个例子,我可能会把你的代码改成这样的东西(请注意我是在没有测试运行的情况下写的,所以可能有一些错误):

我将您的列表条目更改为:

public class CustomList {

    public String iconUrl;
    public String title;
    public CustomList(){
        super();
    }

    public CustomList(String icon, String title) {
        super();
        this.icon = icon;
        this.title = title;
    }
}

然后只将图标网址传递到您的列表中。

接下来创建一个AsyncTask:

public class ImageDownloader extends AsyncTask<String, Integer, Bitmap> {
     public ImageDownloader(ImageView view){
          mView = view;
     }

     protected Bitmap doInBackground(String... url) {
        Bitmap b = null;
        try {
            URL image_url = new URL(url);
            b = BitmapFactory.decodeStream(image_url.openConnection() .getInputStream());
            list_data = new CustomList[]{
                    new CustomList(b,"Android")};
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return b;
     }

     protected void onPostExecute(Bitmap result) {
         mView.setImageBitmap(result);
     }
     ImageView mView;
}

然后对于您的适配器,而不是设置图像,请执行:

new ImageDownloader(holder.thumbnail).execute(cl.icon);

这应该足以让你入门。请注意,此示例存在以下几个问题:

  1. 可能存在内存泄漏。一般来说你应该 不得持有对观点或活动(或其他此类观点)的引用 像我这样的AsyncTask中的对象。
  2. 如果您旋转手机并且 列表更改,您可能会显示旧的缩略图。
  3. 如果是 视图已被回收,旧的缩略图可能会显示出来。