0

我在这里关注 developer.android 网站,我正在尝试从 url 加载大图像(即 1024 x 900)我的代码在我的 Google Nexus 中运行良好,但在 Nexus 上不起作用。

这是我的代码

public static Bitmap getBitmapFromURL(String src) {
        Bitmap bmImg;
        URL myFileUrl = null;

        try {
            myFileUrl = new URL(src);

            HttpURLConnection conn= (HttpURLConnection)myFileUrl.openConnection();
            conn.setDoInput(true);
            conn.connect();
            InputStream is = conn.getInputStream();


            final BitmapFactory.Options options = new BitmapFactory.Options();

            BufferedInputStream bis = new BufferedInputStream(is, 4*1024);
            ByteArrayBuffer baf = new ByteArrayBuffer(50);
            int current = 0;
            while ((current = bis.read()) != -1) {
                baf.append((byte)current);
            }
            byte[] imageData = baf.toByteArray();

            BitmapFactory.decodeByteArray(imageData, 0, imageData.length, options);
            options.inJustDecodeBounds = true;
            options.inSampleSize = calculateInSampleSize(options, 1024, 128);
            options.inJustDecodeBounds = false;
            Bitmap bitmap = BitmapFactory.decodeByteArray(imageData, 0, imageData.length,options);
            return bitmap;
        } catch (Exception e) {
            // TODO Auto-generated catch block
            return null;
        }
    } 

public static int calculateInSampleSize(
            BitmapFactory.Options options, int reqWidth, int reqHeight) {
        // Raw height and width of image
        // Raw height and width of image
        final int height = options.outHeight;
        final int width = options.outWidth;
        int inSampleSize = 1;

        if (height > reqHeight || width > reqWidth) {

            final int halfHeight = height / 2;
            final int halfWidth = width / 2;

            // Calculate the largest inSampleSize value that is a power of 2 and keeps both
            // height and width larger than the requested height and width.
            while ((halfHeight / inSampleSize) > reqHeight
                    && (halfWidth / inSampleSize) > reqWidth) {
                inSampleSize *= 2;
            }
        }

        return inSampleSize;
    }

异步任务类

class BitmapWorkerTask extends AsyncTask<String, Void, Bitmap> {
        private final WeakReference<ImageView> imageViewReference;
        private String data = null;

        public BitmapWorkerTask(ImageView imageView) {
            // Use a WeakReference to ensure the ImageView can be garbage collected
            imageViewReference = new WeakReference<ImageView>(imageView);
        }

        // Decode image in background.
        @Override
        protected Bitmap doInBackground(String... params) {
            data = params[0];
            return Util.getBitmapFromURL(data);
        }

        // Once complete, see if ImageView is still around and set bitmap.
        @Override
        protected void onPostExecute(Bitmap bitmap) {
            if (imageViewReference != null && bitmap != null) {
                final ImageView imageView = imageViewReference.get();
                if (imageView != null) {
                    imageView.setImageBitmap(Bitmap.createBitmap(bitmap, 0, bitmap.getHeight()/2, bitmap.getWidth(), bitmap.getHeight()/2));
                }
            }
        }
    }

当我在 Nexus 上运行时,出现内存不足异常。在关注 android 开发者网站时,我不明白我在这里做错了什么以及为什么我的应用程序在旧设备中崩溃。请帮忙。

注意:我的图像宽度应始终为 match_parent。这就是为什么我把 calculateInSampleSize(option, 1024 ,128)

4

3 回答 3

1

您正在浪费内存,因为您在解码整个图像后设置了 inJustDecodeBounds 。(我猜你以后会因为这个而得到OOM)。考虑关闭您的输入流。

  BitmapFactory.decodeByteArray(imageData, 0, imageData.length, options);
  options.inJustDecodeBounds = true;
  options.inSampleSize = calculateInSampleSize(options, 1024, 128);
  options.inJustDecodeBounds = false;
  Bitmap bitmap = BitmapFactory.decodeByteArray(imageData, 0, imageData.length,options);
  return bitmap;

我认为你真的打算这样做:

  options.inJustDecodeBounds = true;
  BitmapFactory.decodeByteArray(imageData, 0, imageData.length, options);
  options.inSampleSize = calculateInSampleSize(options, 1024, 128);
  options.inJustDecodeBounds = false;
  Bitmap bitmap = BitmapFactory.decodeByteArray(imageData, 0, imageData.length,options);
  return bitmap;

这将在不存储位图的情况下获得图像的宽度和高度(只需获取选项),然后对图像进行二次采样以正确的大小并返回位图。

我不明白你为什么在 onPostExexute 你的异步任务中再次调整位图的大小, imageView.setImageBitmap(Bitmap.createBitmap(bitmap, 0, bitmap.getHeight()/2, bitmap.getWidth(), bitmap.getHeight()/2));

当您刚刚完成加载位图时,为什么不加载正确的大小开始呢?(在完成上述更改后,我建议您记录尺寸并查看您是否真的需要再次调整尺寸 onPostExexute

你看过图片加载库吗?

有很多可用的,似乎适合您需要的是毕加索

在哪里可以做这样的事情: Picasso.with(context).load("url_to_image").fit().into(imageView);

这会下载并缓存位图(在后台线程中)并适合并绘制到 imageView 中,所有这些都在一条线上,整洁!

于 2013-12-21T15:02:54.933 回答
0

您必须在not in 中进行Bitmap提取,在 a 中执行此操作,否则您的应用程序将内存不足。ThreadMain threadAsyncTask

在你的getBitmapFromURL()工作doInBackground方法范围内完成工作Asynctask

于 2013-12-20T06:50:31.720 回答
-1

在您的清单中:添加android:largeHeap=true到您的应用程序选项卡。

于 2013-12-20T06:46:00.313 回答