2014-11-14 58 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