2012-05-15 2 views
1

Link.Утечка памяти Android

Теперь у меня есть утечка контекста в моем проекте, и по ссылке он в значительной степени объясняет все, что может вызвать это.

Чтобы быть честным, я попытался удалить как можно больше переменных с переменными контекста, но у меня возникла проблема с моим Grid View и моим базовым адаптером, и мне действительно нужна помощь. Я стучал головой по этому поводу. Иногда он ускользает от меня, что он собирает мусор, и показывает себя как ниндзя на других классах.

Мой вопрос: «Что вы, ребята, предложите мне изменить?» и «Чего я должен следить?»

Вот что я сделал: 1. Создал карту Hash для моих рисуемых образов 2. Создан Базовый адаптер для GridView 3. Моего кода для класса loadCover

частного статических карт ImageLocator = Коллекции .synchronizedMap (новый 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

Смежные вопросы