2013-02-03 14 views
6

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

メモリが不足することなくImageViewTouch(ImageView)に大きな画像を読み込む方法を教えてください。

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 
+0

にhttp://のstackoverflowを。 com/a/24135283/294884 – Fattie

答えて

2

のどのバージョンを今、私は単純に、この(AsyncTask)を使用していることで

OSでこれをテストしていますか?以前のバージョンでは、使用可能なヒープスペースは、後のバージョンよりもずっと低くなっています。

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

具体的なImageViewのサイズに合わせて適切な画像を読み込む方法の詳細については、this articleを読むことをおすすめします。

最後に、あなたは常にfinallyブロックにInputStreamを閉じる必要があります。また、あなたは具体的には、写真編集アプリケーションなどの大きなビットマップを扱うアプリケーションのために作られた、と考えることができandroid:largeHeap="true"あり

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

+0

回答ありがとうございます。私のターゲットSDKのバージョンは15で、最小は4です。私はすでに記事を読んでいますが、それは助けにはなりませんでした。ここでの問題は、画像を拡大または縮小できないことです。ズーム。 – michalsol

+0

私はあなたに嘘をつきません。メモリに2000x1000イメージを収める答えを見つけることはできません。あなたが何をしていても、利用可能なヒープスペースを超過することはありません。現在のビューポートに基づいて新しいウィンドウをすばやく再読み込みすると、Chromeウェブブラウザがどのように動作し、メモリ内の画像の一部のみがレンダリングされるかのようなさまざまな戦略を見つけることができます。 – dnkoutso

+0

私はそれについて考えました - 画像のズーム部分を再読み込みしましたが、実装するのは非常に困難です。チュートリアルはありますか?ありがとう! – michalsol

2

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

私はプロセスが69560740バイトを割り当てようとしていますが、それは約66MByteです。

最悪の場合、2000x1000は約2000x1000x4 = 8MBytes、つまり66MBytes未満です。他に何かが起こっている。

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

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; 
    } 
+0

私の以前の回答に追加のコメントとして。 VMは69,500,000バイトを割り当てようとするので、あなたのサーバーは非常に大きなイメージを返すと思います。これは、ほぼ3000x3000ピクセルのARGB_8888画像になります。 –

+0

このソリューションは私のメモリ使用量を大幅に改善しました。私はちょうどあなたが言ったことをやっていました。「AsyncTasksの戻り値/結果値としてビットマップを使う問題が見つかりました.......」 あなたが言ったようにコードを修正しました。クラッシュすることなくx2倍の画像が得られます。ありがとうございました –

関連する問題