6

ズーム可能な画像を表示するために使用する ViewPager があります( ImageViewTouchを使用)。インターネット (http) から大きなビットマップをロードする必要があります。概して、2000x1000 を意味します。ズーム可能で詳細を表示する必要があるため、画像は非常に大きくする必要があります。サーバー上の画像は .jpg 形式ですが、問題ありません。変更できます。

メモリの問題を起こさずに、非常に大きな画像を ImageViewTouch (ImageView) にロードするにはどうすればよいですか?

今では単純にこれを使用しています (AsyncTask):

    ImageView currentView; //ImageView where to place image loaded from Internet
    String ImageUrl; //URL of image to load

    protected Bitmap doInBackground(ArrayList... params) {

            Bitmap bitmap;
            InputStream in = null;
            imageUrl = (String)params[0].get(1);

            try{
                HttpClient httpclient = new DefaultHttpClient();
                HttpResponse response = httpclient.execute(new HttpGet(imageUrl));
                in = response.getEntity().getContent();
            } catch(Exception e){
                e.printStackTrace();
            }
            try {
                bitmapa = BitmapFactory.decodeStream(in);
                in.close();
            } catch (IOException e1) {
                e1.printStackTrace();
            }

            return bitmap;
        }


        @Override
        protected void onPostExecute(Bitmap bitmap) {

            currentView.setImageBitmap(bitmap);
        }

そして、それはメモリに多くの問題を引き起こします:

E/dalvikvm-heap(369): 69560740-byte external allocation too large for this process.
E/GraphicsJNI(369): VM won't let us allocate 69560740 bytes

また

E/AndroidRuntime(369): java.lang.RuntimeException: An error occured while executing doInBackground()
E/AndroidRuntime(369):  at android.os.AsyncTask$3.done(AsyncTask.java:200)
E/AndroidRuntime(369):  at java.util.concurrent.FutureTask$Sync.innerSetException(FutureTask.java:274)
E/AndroidRuntime(369):  at java.util.concurrent.FutureTask.setException(FutureTask.java:125)
E/AndroidRuntime(369):  at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:308)
E/AndroidRuntime(369):  at java.util.concurrent.FutureTask.run(FutureTask.java:138)
E/AndroidRuntime(369):  at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1088)
E/AndroidRuntime(369):  at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:581)
E/AndroidRuntime(369):  at java.lang.Thread.run(Thread.java:1019)
E/AndroidRuntime(369): Caused by: java.lang.OutOfMemoryError: bitmap size exceeds VM budget
E/AndroidRuntime(369):  at android.graphics.BitmapFactory.nativeDecodeStream(Native Method)
E/AndroidRuntime(369):  at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:470)
E/AndroidRuntime(369):  at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:525)
E/AndroidRuntime(369):  at com.package.app.ImageDownloader.doInBackground(ImageDownloader.java:78)
E/AndroidRuntime(369):  at com.package.app.ImageDownloader.doInBackground(ImageDownloader.java:1)
E/AndroidRuntime(369):  at android.os.AsyncTask$2.call(AsyncTask.java:185)
E/AndroidRuntime(369):  at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:306)
E/AndroidRuntime(369):  ... 4 more
4

2 に答える 2

2

これをテストする OS のバージョンは何ですか? 以前のバージョンでは、使用可能なヒープ領域が後のバージョンよりもはるかに少なくなっています。

これを避けるために、ビットマップのサイズを縮小することを真剣に検討します。mdpi 電話用に 2000x1000 をダウンロードする場合Bitmap、これはおそらく悪い考えです。

また、サイズに基づいて特定の に適切な画像を正確にロードする方法の詳細については、この記事を読むことをお勧めします。ImageView

InputStream最後に、finallyブロック内のを常に閉じる必要があります。

try {
        bitmap = BitmapFactory.decodeStream(in);
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        if (in != null) { in.close(); }
    }

android:largeHeap="true"写真編集アプリなど、大きなビットマップを扱うアプリ向けに特別に作成された、検討できるものもあります。

于 2013-02-03T16:18:25.440 に答える
2

2000x1000 ピクセルの画像は大きいですが、それほど大きくはありません。

プロセスが終了する前に 69560740 バイトを割り当てようとしていることがわかりますが、それは約 66MByte です!

あなたの 2000x1000 は、最悪の場合、約 2000x1000x4 = 8MBytes で、66MBytes よりはるかに少ないです。他にも何かが起こっています。

また、ビットマップを AsyncTasks の戻り値/結果値として使用する際の問題も見つかりました。終了した AsyncTask は、ガベージ コレクションが行われるまで結果を保持します。AsyncTask インスタンスのガーバージ コレクションを制御しないため、Bitmap を戻り値/結果値として使用しないでください。代わりにビットマップをフィールドに入れて、doInBackground が終了しようとしているときに割り当て、このフィールドを使用して onPostExecute でビットマップを取得し、(!) このフィールドを null に設定します。

Bitmap bitmap;
protected Void doInBackground(ArrayList... params) {

        InputStream in = null;
        imageUrl = (String)params[0].get(1);

        try{
            HttpClient httpclient = new DefaultHttpClient();
            HttpResponse response = httpclient.execute(new HttpGet(imageUrl));
            in = response.getEntity().getContent();
        } catch(Exception e){
            e.printStackTrace();
        }
        try {
            bitmap = BitmapFactory.decodeStream(in);
            in.close();
        } catch (IOException e1) {
            e1.printStackTrace();
        }

        return null;
    }


    @Override
    protected void onPostExecute(Void unused) {
        if (bitmap != null) {
            currentView.setImageBitmap(bitmap);
        }

        // And don't forget to null the bitmap field!
        bitmap = null; 
    }
于 2013-02-06T00:55:06.487 に答える