2012-05-15 222 views
1

LinkAndroid內存泄漏

現在我在我的項目和鏈接上有一個上下文泄漏,它幾乎可以解釋可能導致它的所有事情。

說實話,我試圖儘可能多地刪除有上下文變量,但我的網格視圖和我的基礎適配器有問題,我真的需要幫助,我一直在敲我的頭。有時它會讓我無法收集垃圾,然後在其他類中顯示爲忍者。

我的問題:「你們會建議我應該改變什麼?」和「我應該注意什麼?」

這是我做的:1。 創建一個哈希表爲我創建了一個底座適配器爲GridView繪製圖像 2. 3.我對loadCover類代碼

私有靜態地圖ImageLocator =集合.synchronizedMap(new WeakHashMap());

private class BaseA extends BaseAdapter{ 
    private LayoutInflater inflater; 

    public BaseA(Context context){ 
     inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); 
    } 

    public View getView(int position, View convertView, ViewGroup parent) { 
     // TODO Auto-generated method stub 
     View row = convertView; 
     viewHolder vh = new viewHolder(); 

     row = inflater.inflate(R.layout.book_row_view, null);  
     vh.authors = (TextView)row.findViewById(R.id.book_Author); 
     vh.image = (ImageView)row.findViewById(R.id.icon); 
     vh.date = (TextView)row.findViewById(R.id.Date); 
     vh.Titles = (TextView)row.findViewById(R.id.Book_Title); 
     vh.fileName = (TextView)row.findViewById(R.id.FileLocation); 

     try{ 
      String temp = File_Name.get(position); 
      vh.fileName.setText(temp); 
     }catch (Exception e) { 
      // TODO: handle exception 
      e.printStackTrace(); 
     } 

     Book_Information bi; 
     bi = new Book_Information(); 
     bi = dbh.getData(File_Name.get(position)); 
     //Gets the right book information for all the items 
     new LoadCover(vh.image, bi).run(); 
     if(bi.getBook_Author() != null || bi.getBook_Date() !=null || bi.getBook_Description() != null || 
       bi.getBook_Title() != null){ 

      vh.authors.setText(bi.getBook_Author()); 
      vh.date.setText(bi.getBook_Date()); 
      vh.Titles.setText(bi.getBook_Title()); 
     }     
     return row; 
    } 

    public int getCount() { 
     // TODO Auto-generated method stub 
     return File_Name.size(); 
    } 

    public Object getItem(int position) { 
     // TODO Auto-generated method stub 
     return position; 
    } 

    public long getItemId(int position) { 
     // TODO Auto-generated method stub 
     return position; 
    } 

} 



private class LoadCover implements Runnable{ 
    ImageView image; Book_Information bi; 

    public LoadCover(ImageView image, Book_Information bi){ 
     this.image = image; 
     this.bi = bi; 
    } 

    public void run() { 
     // TODO Auto-generated method stub 
     Drawable draw = ImageLocator.get(bi.getBook_File_Name()); 

     if(draw!=null){ 
      image.setImageDrawable(draw); 
     }else{ 
      new UpdateImages(image, bi).run(); 
     } 
     draw = null; 
    } 


} 

private class UpdateImages implements Runnable{ 
    ImageView image; 
    Book_Information book_info; 

    public UpdateImages(ImageView imageView, Book_Information bookInfo){ 
     this.image = imageView; 
     this.book_info = bookInfo; 
    } 
    public void run(){ 
     try{ 
      Bitmap bm = getBitmap(book_info); 
      FastBitmapDrawable fbd = new FastBitmapDrawable(bm); 
      image.setImageDrawable(fbd); 
      ImageLocator.put(book_info.getBook_File_Name(), fbd); 
      bm = null; 
     }catch (OutOfMemoryError e) { 
      // TODO: handle exception 
      ImageLocator.clear(); 
     } 
    } 
} 
+0

我只是掃了一眼,但傳遞的ImageView進入LoadCover可能會導致問題,當您在活動被銷燬後繼續保留它時,您仍然可以使用它內存中的活動 – Blundell

+0

我應該把它變成一種方法嗎?這樣每次滾動它都會被覆蓋? – sdfwer

+0

你知道你唯一的實現Runnable,那實際上並不意味着它運行在它自己的ThreaD上? – Blundell

回答

3

我看着你的代碼和重構它變成一個更易於管理的方式,指出了幾件事情。

您在getView方法中執行某種類型的圖像加載時,這需要很長時間,應該在ASyncTask或具有某種回調類型的處理程序中完成。

然後,您將這些位圖存儲在靜態地圖中,該靜態地圖將保留在您的應用程序的整個生命週期的內存中,這是baaad並在創建位圖時保留對上下文的引用。我可以看到您將它用作加載時的圖像緩存,如果這會導致內存不足錯誤,可能會想到另一種方式。

這裏是你的代碼,重構:

/** 
* @author paul.blundell 
*   May 15, 2012 
*/ 
public class MyAct extends Activity { 

    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 

     LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE); 
     List<String> fileNames = new ArrayList<String>(); // Whatever filenames you get 
     List<BookInformation> list = dbh.getData(fileNames); // However you get your data from the database (usually in a Service) 

     BaseA base = new BaseA(inflater, list); 

     // Do whatever with base 
    } 
} 

適配器類:

public class BaseA extends BaseAdapter { 

     // Having a static map means it lives the entire life of your application, your drawables should take a context 
     // when they are being created therefore they have a reference to your Activity, and this is not being destroyed 
     public static Map<String, Drawable> imageLocator = new WeakHashMap<String, Drawable>(); 

     private LayoutInflater inflater; 
     private List<BookInformation> books; 

     public BaseA(LayoutInflater inflater, List<BookInformation> books) { 
      this.inflater = inflater; 
      this.books = books; 
     } 

     public View getView(int position, View convertView, ViewGroup parent) { 
      View rowView = convertView; 
      ViewHolder vh = null; 

      if(rowView == null){ 
       // Get new instance of our row view 
       rowView = inflateView(); 
       // Hold the view in an object so it doesnt need to be re-fetched 
       vh = new ViewHolder(); 

       vh.authors = (TextView) rowView.findViewById(R.id.book_author); 
       vh.image = (ImageView) rowView.findViewById(R.id.book_icon); 
       vh.date  = (TextView) rowView.findViewById(R.id.book_date); 
       vh.titles = (TextView) rowView.findViewById(R.id.book_title); 
       vh.fileName = (TextView) rowView.findViewById(R.id.file_location); 

       // Cache the view so it can be re-accessed later 
       rowView.setTag(vh); 
      } else { 
       vh = (ViewHolder) rowView.getTag(); 
      } 

      BookInformation book = books.get(position); 
      vh.fileName.setText(book.getFileName()); 

      // Gets the right book information for all the items 
      loadCover(vh.image, book.getFileName()); 

      if (book.getAuthor() != null){ 
       vh.authors.setText(book.getAuthor()); 
      } 
      if(book.getDate() != null){ 
       vh.date.setText(book.getDate()); 
      } 
      if(book.getTitle() != null){ 
       vh.titles.setText(book.getTitle()); 
      } 

      return rowView; 
     } 

     private View inflateView() { 
      return inflater.inflate(R.layout.view_book_row, null); 
     } 

     public int getCount() { 
      return books.size(); 
     } 

     public Object getItem(int position) { 
      return position; 
     } 

     public long getItemId(int position) { 
      return position; 
     } 

     private void loadCover(ImageView image, String filename) { 
      Drawable draw = imageLocator.get(filename); 

      if (draw == null) { 
       draw = updateImage(filename); 
      } 
      imageLocator.put(filename, draw); // This is your problem keeping a reference to these drawables in a static map 
      image.setImageDrawable(draw); 
     } 

     private Drawable updateImage(String filename) { 
      Bitmap bm = getBitmap(filename); 
      Drawable drawable = new BitmapDrawable(bm); 
      return drawable; 
     } 

     private Bitmap getBitmap(String filename) { 
      return null; // I don't know how you get a bitmap but you shouldn't do this in getView() , use a callback 
     } 

     private static class ViewHolder { 
      public TextView fileName; 
      public TextView titles; 
      public TextView date; 
      public ImageView image; 
      public TextView authors; 
     } 
    } 

獨立域名類bookInformation:

public class BookInformation { 

     public String getFileName() { 
      return "filename"; 
     } 

     public String getTitle() { 
      return "title"; 
     } 

     public String getDate() { 
      return "date"; 
     } 

     public String getAuthor() { 
      return "author"; 
     } 
    } 
+0

是的你是對的。我應該把它放在我的基地適配器的哈希映射。感謝有關數據庫處理程序的信息。 – sdfwer