2014-11-14 64 views
2

我是Android開發新手。我試圖通過HTTP下載圖像並將它們存儲在ImageView或Drawable中。在這個例子中,我使用ImageViews。最初,我使用了一個AsyncTask來下載這些圖像(每個大約500KB),然而我決定使用畢加索,因爲我已經讀了它更可靠。Android Picasso ImageView - 內存不足異常MemoryLeak

在下面的代碼中,我有20個ImageViews。每個圖片網址都是大約400KB的圖片。但是,加載所有這些後,我注意到我的getUsedMem()大於100MB。我不確定是什麼導致了這種內存泄漏。

你能幫我嗎?

public class Example extends Activity { 
    public long getUsedMem() 
    { 
     long freeSize = 0L; 
     long totalSize = 0L; 
     long usedSize = -1L; 
     try { 
      Runtime info = Runtime.getRuntime(); 
      freeSize = info.freeMemory(); 
      totalSize = info.totalMemory(); 
      usedSize = totalSize - freeSize; 
     } catch (Exception e) { 
      e.printStackTrace(); 
     } 

     return usedSize; 
    } 

    public void concatLogMessages(String msg) 
    { 
     TextView tv = (TextView) findViewById(R.id.textView1); 
     CharSequence cs = tv.getText(); 

     tv.setText(cs + "\n" + 
        "Image #: " + msg + "\n" + 
        "Used Mem: " + getUsedMem() 
        ); 
    } 

    public void loadImage(final ImageView target, String url, final int num) { 
     Picasso.with(this).load(url).into(target, new EmptyCallback(){ 
      @Override 
      public void onError() { 
       Example.this.concatLogMessages("Picasso onError"); 
       super.onError(); 
      } 

      @SuppressLint("NewApi") @Override 
      public void onSuccess() { 
       Example.this.concatLogMessages("Picasso onSuccess " + num); 
       super.onSuccess(); 
      } 
     }); 
    } 

    @SuppressLint("NewApi") 
    @Override 
    public void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.main); 

     drawables = new ArrayList<Drawable>(); 

     // Check Memory Before Everything 
     concatLogMessages("0"); 

     // Imageview to show 
     ImageView image1 = (ImageView) findViewById(R.id.imageView1); 
     ImageView image2 = (ImageView) findViewById(R.id.imageView2); 
     ImageView image3 = (ImageView) findViewById(R.id.imageView3); 
     ImageView image4 = (ImageView) findViewById(R.id.imageView4); 
     ImageView image5 = (ImageView) findViewById(R.id.imageView5); 
     ImageView image6 = (ImageView) findViewById(R.id.imageView6); 
     ImageView image7 = (ImageView) findViewById(R.id.imageView7); 
     ImageView image8 = (ImageView) findViewById(R.id.imageView8); 
     ImageView image9 = (ImageView) findViewById(R.id.imageView9); 
     ImageView image10 = (ImageView) findViewById(R.id.imageView10); 
     ImageView image11 = (ImageView) findViewById(R.id.imageView11); 
     ImageView image12 = (ImageView) findViewById(R.id.imageView12); 
     ImageView image13 = (ImageView) findViewById(R.id.imageView13); 
     ImageView image14 = (ImageView) findViewById(R.id.imageView14); 
     ImageView image15 = (ImageView) findViewById(R.id.imageView15); 
     ImageView image16 = (ImageView) findViewById(R.id.imageView16); 
     ImageView image17 = (ImageView) findViewById(R.id.imageView17); 
     ImageView image18 = (ImageView) findViewById(R.id.imageView18); 
     ImageView image19 = (ImageView) findViewById(R.id.imageView19); 
     ImageView image20 = (ImageView) findViewById(R.id.imageView20); 

     /* Picasso */ 
     ImageView target = (ImageView) findViewById(R.id.picassoImageView); 

     loadImage(target, image_url1, 0); 

     // Test 1-20 image views... 
     loadImage(image1, R.String.image_url1, 1); 
     loadImage(image2, R.String.image_url2, 2); 
     loadImage(image3, R.String.image_url3, 3); 
     loadImage(image4, R.String.image_url4, 4); 
     loadImage(image5, R.String.image_url5, 5); 
     loadImage(image6, R.String.image_url6, 6); 
     loadImage(image7, R.String.image_url7, 7); 
     loadImage(image8, R.String.image_url8, 8); 
     loadImage(image9, R.String.image_url9, 9); 
     loadImage(image10, R.String.image_url10, 10); 
     loadImage(image11, R.String.image_url11, 11); 
     loadImage(image12, R.String.image_url12, 12); 
     loadImage(image13, R.String.image_url13, 13); 
     loadImage(image14, R.String.image_url14, 14); 
     loadImage(image15, R.String.image_url15, 15); 
     loadImage(image16, R.String.image_url16, 16); 
     loadImage(image17, R.String.image_url17, 17); 
     loadImage(image18, R.String.image_url18, 18); 
     loadImage(image19, R.String.image_url19, 19); 
     loadImage(image20, R.String.image_url20, 20); 
    } 
} 
+0

看看[這裏](http://stackoverflow.com/questions/477572/) –

回答

5

我不認爲這是泄漏。

當Android「展開」圖像(即將其解碼爲位圖)時,它將使用每像素4個字節。計算像素數量,乘以4,然後乘以20(圖像數量),您可能會接近100mb的數字。例如,如果您的圖像具有1,000,000像素的分辨率,則會是1,000,000 x 4 x 20 = 80mb。

您不應該一次加載所有這些圖像。使用某種類型的LRU緩存或類似的(或者使用通用圖像加載程序庫來爲您處理緩存),並只在需要時加載您的位圖。

我強烈建議你閱讀這篇文章,並在密切關注其建議: http://developer.android.com/training/displaying-bitmaps/load-bitmap.html

+0

非常感謝你提供這個信息Kha。我會研究並閱讀LRU緩存算法,你會推薦LRU優於其他緩存算法嗎?另外,你有沒有推薦使用通用圖像加載程序?畢加索是不是有能力?是否Volley庫適合這個? – codeshark

+0

我指的是這個庫:https://github.com/nostra13/Android-Universal-Image-Loader。它很容易使用,可以爲你處理各種緩存,你仍然會d自己提供URI(文件位置等),但它應該爲您處理剩餘的URI。它也是高度可配置的。 – kha

1

我用這對大量的圖像,並能正常工作

private class LoadImage extends AsyncTask<String, String, Bitmap> { 

    @Override 
    protected void onPreExecute() { 
     super.onPreExecute(); 
     pDialog = new ProgressDialog((Main)context); 
     pDialog.setMessage("Loading Image ...."); 
     pDialog.show(); 
    } 
    protected Bitmap doInBackground(String... args) { 
      Log.i("doInBack 1","length = 1 "); 
      try { 
       Bitmap positivo = BitmapFactory.decodeStream((InputStream)new URL(args[0]).getContent()); 
      } catch (Exception e) { 
       e.printStackTrace(); 
      } 

     return positivo; 
    } 
    protected void onPostExecute(Bitmap image) { 
     if(image != null){ 
      //*bitmap is the bitmap u change each time 
      bitmap = image; 
      invalidate(); 
      pDialog.dismiss(); 
     } 
    } 

如何調用這個?寫這當u想要改變形象正好與URL

new LoadImage().execute("https://yourimage.jpg"); 
+0

感謝你爲這個安德烈斯。如果我在單個Activity上的20個ImageView項目上運行這20次,是否會增加已用內存的很多? – codeshark

+0

你需要同時看20張圖嗎? –

+0

是:(我看到大約120MB的已用內存 – codeshark