-3

我正在使用GridView和universalimageloader(1.8.6),似乎遇到内存泄漏 - 虽然也许我误解了DDMS和MAT结果?这是我没有写的代码,但它非常基础 - 我们展示了许多照片,并允许用户选择他们想要的数量,然后存储这些照片以供将来参考。该代码似乎工作正常,但在MAT“泄漏可疑”从下面的GridView不断显示,每次咀嚼高达5 MB,即使我已经在Activity上调用finish()。从我读过的内容来看,Android可以将Activity保留在内存中,直到它释放它(并且已经在其他活动中看到了这一点),但它似乎从未想要释放这个 - 即使当我强制GC时。 “新线程”分配看起来有点可疑,但不会被调用活动取消分配?内存泄漏和GridView

也许只是缺少明显的东西,但这里是代码:

public class PhotoGalleryPickerActivity extends MyActivity { 

private Boolean mMultiple = false; 

GridView gridGallery; 
Handler handler; 
GalleryAdapter adapter; 

ImageView imgNoMedia; 
Button btnGalleryOk; 

String action; 
private ImageLoader imageLoader; 


@Override 
public void onActivityResult(int requestCode, int resultCode, Intent data) { 

} 

@Override 
protected void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    setContentView(R.layout.activity_photo_gallery_picker); 

    ActionBar actionBar = getActionBar(); 
    actionBar.setDisplayHomeAsUpEnabled(true); 
    actionBar.setTitle("Photo Gallery Capture"); 

    Bundle extras = getIntent().getExtras(); 
    mMultiple = extras.getBoolean("multiple"); 

    initImageLoader(); 
    init(); 
} 


private void initImageLoader() { 
    try { 
     String CACHE_DIR = Environment.getExternalStorageDirectory().getAbsolutePath() + "/.temp_tmp"; 
     new File(CACHE_DIR).mkdirs(); 

     File cacheDir = StorageUtils.getOwnCacheDirectory(getBaseContext(), CACHE_DIR); 

     DisplayImageOptions defaultOptions = new DisplayImageOptions.Builder() 
       .cacheOnDisc(true).imageScaleType(ImageScaleType.EXACTLY) 
       .bitmapConfig(Bitmap.Config.RGB_565).build(); 
     ImageLoaderConfiguration.Builder builder = new ImageLoaderConfiguration.Builder(
       getBaseContext()) 
       .defaultDisplayImageOptions(defaultOptions) 
       .discCache(new UnlimitedDiscCache(cacheDir)) 
       .memoryCache(new WeakMemoryCache()); 

     ImageLoaderConfiguration config = builder.build(); 
     imageLoader = ImageLoader.getInstance(); 
     imageLoader.init(config); 

    } catch (Exception e) { 
     Utilities.logException(e); 
    } 
} 

private void init() { 

    handler = new Handler(); 
    gridGallery = (GridView) findViewById(R.id.gridGallery); 
    gridGallery.setFastScrollEnabled(true); 
    adapter = new GalleryAdapter(getApplicationContext(), imageLoader); 
    PauseOnScrollListener listener = new PauseOnScrollListener(imageLoader, true, true); 
    gridGallery.setOnScrollListener(listener); 

    if (mMultiple == true){ 
     findViewById(R.id.llBottomContainer).setVisibility(View.VISIBLE); 
     gridGallery.setOnItemClickListener(mItemMulClickListener); 
     adapter.setMultiplePick(true); 
    } 
    else { 
     findViewById(R.id.llBottomContainer).setVisibility(View.GONE); 
     gridGallery.setOnItemClickListener(mItemSingleClickListener); 
     adapter.setMultiplePick(false); 
    } 

    gridGallery.setAdapter(adapter); 
    imgNoMedia = (ImageView) findViewById(R.id.imgNoMedia); 

    btnGalleryOk = (Button) findViewById(R.id.btnGalleryOk); 
    btnGalleryOk.setOnClickListener(mOkClickListener); 

    new Thread() { 

     @Override 
     public void run() { 
      Looper.prepare(); 
      handler.post(new Runnable() { 

       @Override 
       public void run() { 
        adapter.addAll(getGalleryPhotos()); 
        checkImageStatus(); 
       } 
      }); 
      Looper.loop(); 
     }; 

    }.start(); 

} 

private void checkImageStatus() { 
    if (adapter.isEmpty()) { 
     imgNoMedia.setVisibility(View.VISIBLE); 
    } else { 
     imgNoMedia.setVisibility(View.GONE); 
    } 
} 

View.OnClickListener mOkClickListener = new View.OnClickListener() { 

    @Override 
    public void onClick(View v) { 
     ArrayList<CustomGallery> selected = adapter.getSelected(); 

     String[] photos = new String[selected.size()]; 
     for (int i = 0; i < photos.length; i++) { 
      photos[i] = selected.get(i).sdcardPath; 
     } 

     Intent data = new Intent().putExtra("photos", photos); 
     if(photos.length == 0) { 
      data = null; 
     } 
     setResult(RESULT_OK, data); 
     finish(); 

    } 
}; 
AdapterView.OnItemClickListener mItemMulClickListener = new AdapterView.OnItemClickListener() { 

    @Override 
    public void onItemClick(AdapterView<?> l, View v, int position, long id) { 
     adapter.changeSelection(v, position); 

    } 
}; 

AdapterView.OnItemClickListener mItemSingleClickListener = new AdapterView.OnItemClickListener() { 

    @Override 
    public void onItemClick(AdapterView<?> l, View v, int position, long id) { 
     CustomGallery item = adapter.getItem(position); 
     String[] photos = new String[1]; 
     photos[0] = item.sdcardPath; 
     Intent data = new Intent().putExtra("photos", photos); 
     setResult(RESULT_OK, data); 
     finish(); 
    } 
}; 

private ArrayList<CustomGallery> getGalleryPhotos() { 
    ArrayList<CustomGallery> galleryList = new ArrayList<CustomGallery>(); 

    try { 
     String[] dirs = new String[1]; 
     final String where = MediaStore.Images.Media.DATA + " not like ? "; 
     String mediaDir = GlobalState.getInstance().currentForm.mediaDirectory(); 
     if (mediaDir != null) { 
      int slash = mediaDir.lastIndexOf("/"); 
      dirs[0] = mediaDir.substring(0, slash) + "%"; 
     } 
     final String[] columns = { MediaStore.Images.Media.DATA, MediaStore.Images.Media._ID }; 
     final String orderBy = MediaStore.Images.Media._ID; 

     Cursor imagecursor = null; 
     try { 
      if (mediaDir != null && mediaDir.trim().length() > 0) { 
       imagecursor = getContentResolver().query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, columns, where, dirs, orderBy); 
      } 
      else { 
       imagecursor = getContentResolver().query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, columns, null, null, orderBy); 
      } 

      if (imagecursor != null && imagecursor.getCount() > 0) { 

       while (imagecursor.moveToNext()) { 
        CustomGallery item = new CustomGallery(); 

        int dataColumnIndex = imagecursor 
          .getColumnIndex(MediaStore.Images.Media.DATA); 

        item.sdcardPath = imagecursor.getString(dataColumnIndex); 

        galleryList.add(item); 
       } 
      } 
     } 
     catch (Exception ex) { 
      Utilities.logException(ex); 
      Utilities.logError("PhotoGalleryPickerActivity", "getGalleryPhotos : " + ex.getMessage()); 
     } 
     finally { 
      if (imagecursor != null) { 
       imagecursor.close(); 
      } 
     } 

    } catch (Exception e) { 
     Utilities.logException(e); 
     e.printStackTrace(); 
    } 

    // show newest photo at beginning of the list 
    Collections.reverse(galleryList); 
    return galleryList; 
} 


@Override 
public boolean onOptionsItemSelected(MenuItem item) { 
    switch (item.getItemId()) { 
     case android.R.id.home: 
      PhotoGalleryPickerActivity.this.finish(); 
      return true; 
    } 
    return super.onOptionsItemSelected(item); 
} 

}

的MAT结果,从Eclipse中运行,这个样子。它显示了所有我对这个活动提出的各种电话,仿佛他们没有实际已发布:

Leak Suspect Detail

Leak Suspect Overview

该应用程序的正常内存周围11-15mb挂起,但你可以看到它现在约为50MB,并且每次我打电话时都会增长。如果所有的犯罪嫌疑人的记忆被回收,我想我会是正确的,我应该是:

Heap Allocation

最后,可这是在Eclipse运行到远程设备的结果呢?我看到与另一个控件类似的东西,无法复制。而我绝对能够复制这一点。

谢谢!

回答

0

只是把这个包起来,问题是new Thread(),这是持有的资源,特别是GridView(在+4mb每命中)。我的最终解决方案是摆脱线程和循环,直接调用Activityinit()中的两种方法。我不知道为什么它被编入一个循环线程开始,虽然我怀疑它可能是更新动态图像列表(或剪切和粘贴的代码,这是不是真正了解)。无论如何,似乎正在工作,内存正在成功收集车库。感谢@dharms你的帮助!