0

ここでdeveloper.android の Web サイトをフォローしています。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;
    }

AsyncTask クラス

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 s で実行すると、メモリ不足の例外が発生します。次の Android 開発者の Web サイトでは、ここで何が間違っていたのか、古いデバイスでアプリケーションがクラッシュする理由がわかりませんでした。助けてください。

注: 画像の幅は常に 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 asynctask でビットマップのサイズを再度変更する理由がわかりません。 imageView.setImageBitmap(Bitmap.createBitmap(bitmap, 0, bitmap.getHeight()/2, bitmap.getWidth(), bitmap.getHeight()/2));

ビットマップのロードが完了したら、最初に正しいサイズをロードしてみませんか? (上記の変更を行った後、サイズをログに記録し、本当に再度サイズ変更する必要があるかどうかを確認することをお勧めします onPostExexute)

画像読み込みライブラリを見たことがありますか?

利用可能なものがかなりありますが、ニーズに合うと思われるのはPicassoです

次のようなことができる場所: Picasso.with(context).load("url_to_image").fit().into(imageView);

これにより、ビットマップが (バックグラウンド スレッドで) ダウンロードおよびキャッシュされ、imageView に適合して描画されます。

于 2013-12-21T15:02:54.933 に答える
0

You must do the Bitmap extraction in Thread not in Main thread , Do this within a AsyncTask Otherwise your app will get out of memory.

Do the work in your getBitmapFromURL() work within doInBackground method of Asynctask

于 2013-12-20T06:50:31.720 に答える
-1

マニフェストで:android:largeHeap=trueアプリケーション タブに追加します。

于 2013-12-20T06:46:00.313 に答える