ListView с getView () переопределено медленно из-за постоянного GC? - PullRequest
3 голосов
/ 23 августа 2011

У меня есть ListView в моем приложении, и я переопределил метод getView (), чтобы я мог изменить src ImageView строки в зависимости от текста строки.

Проблема в том, что я заметил, что прокрутка ListView запаздывает, и когда я проверяю DDMS, кажется, что сборщик мусора вызывается при каждой прокрутке ListView, тем самым замедляя прокрутку.

Я также заметил, что сборщик мусора вызывается в другой части моего приложения при чтении строк из BufferedReader, что делает открытие файла из 2000 строк занимает ~ 47 секунд, тогда как в качестве средства проверки файлов я установил на него телефон открывает тот же файл примерно за 2 секунды.

Итак, мой вопрос: что может вызывать постоянную сборку мусора каждые 200 мс или около того, и как мне предотвратить это? Это действительно замедляет работу моего приложения, и я боюсь, что это оттолкнет некоторых пользователей, если я не решу его.

Спасибо, Алекс.

ListView getView ():

class IconicAdapter extends ArrayAdapter<String> {
  IconicAdapter(){
    super(FileBrowser.this, R.layout.filebrowser_listview_row, R.id.listtext, directoryEntries);
  }

  @Override
  public View getView(int position, View convertView, ViewGroup parent){
    View row = super.getView(position, convertView, parent);
    TextView text = (TextView) row.findViewById(R.id.listtext);
    ImageView icon = (ImageView) row.findViewById(R.id.listicon);

    entryFullFileName = directoryEntries.get(position).toString();

    if(entryFullFileName.contains(".") && !entryFullFileName.matches("^\\.+$")){
      String[] parts = entryFullFileName.split("\\.");
      lastIndex = parts.length - 1;
      fileType = parts[lastIndex];
    }else{
      fileType = "";
    }

     if(fileIsDir.get(position) == true){
      icon.setImageResource(R.drawable.folderlightblue);
     }else if(fileType.equals("html")){
      icon.setImageResource(R.drawable.filehtml);
     }else if(fileType.equals("css")){
      icon.setImageResource(R.drawable.filecss);
     }else if(fileType.equals("js")){
      icon.setImageResource(R.drawable.filejs);
     }else if(fileIsDir.get(position) == false){
      icon.setImageResource(R.drawable.fileplain);
     }

   return(row);
  }
}  

Код для открытия файла

На днях я удалил код, который регистрировал, сколько секунд потребовалось, чтобы открыть файл, но это заняло 47 секунд и определенно заняло слишком много времени, и снова, пока цикл while работает, есть постоянные вызовы сборщику мусора, который я догадываюсь из-за медленного чтения файла - и да, эта функция вызывается в потоке с показом progressDialog во время чтения файла

private String getLocalFileContents(String fileUri){
  try{
    String contents = "";
    BufferedReader in = new BufferedReader(new FileReader(fileUri));
    String line;
    while((line = in.readLine()) != null){
      contents += line + "\n";
    }
    in.close();

    return contents;
  }catch(Exception e){
    toast.setText("Failed to open sdcard file, try again.");
  }
 return null;
}

UPDATE:

Проблема с чтением файла решена, получается, что конкатенация String заставляет сборщик мусора вызываться после каждого цикла, что значительно замедляет чтение файла. Как подсказывает ответ, я вместо этого использовал StringBuilder, и теперь он открывается через секунду - ура!

2-е ОБНОВЛЕНИЕ:

Я знаю причину постоянных вызовов GC при прокрутке моего ListView, это атрибут ListView android: cacheColorHint = "@ android: color / transparent" - но я не знаю обходного пути!

Ответы [ 4 ]

1 голос
/ 23 августа 2011

Одной из оптимизаций было бы прекращение разделения всей строки для получения типа файла. Вы можете использовать что-то вроде

String fileType = "";
int lastDot = entryFullFileName.lastIndexOf(".");
if(lastDot!=-1) {
    fileType = entryFullFileName.substring()
}

Это, конечно, не должно занимать 47 с *. 1004 *

1 голос
/ 23 августа 2011

В общем, сборка мусора происходит потому, что вы создаете слишком много объектов без необходимости. Было бы проще помочь с вашим кодом, но я все равно попробую.

В случае с вашим списком вы, вероятно, воссоздаете свое представление при каждом вызове getView. Вместо этого вам следует повторно использовать convertView, когда это необходимо. Посмотрите мой ответ на этот другой вопрос SO, чтобы узнать, как структурировать ваш getView метод.

Вашу проблему с чтением файлов угадать немного сложнее, но 47-е кажется невероятно длинным для 2000 строк. Вы также создаете объекты в этом цикле?

Обновление:

Так что, очевидно, ваша проблема на самом деле не в самих View объектах, но это вся работа, которую вы делаете каждый раз, когда получаете View. Каждый раз вы выполняете довольно много работы: соответствие RegEx, разбиение строки (и создание связанного строкового объекта) и т. Д. Вы должны как минимум кэшировать результаты этого, чтобы вам не приходилось повторять работу для каждого предмет каждый раз, когда он возвращается в поле зрения.

0 голосов
/ 11 января 2013

Да, android: cacheColorHint = "@ android: color / transparent" вызывает чрезмерный вызов сборщика мусора в некоторых версиях ОС (не уверен, что в новейших версиях это исправлено).

Ну, просто попробуйте не использовать его.Например, я говорил с моими дизайнерами, объяснил им проблему о причине лагов, и они согласились не использовать прозрачный фон.

0 голосов
/ 23 августа 2011

Посмотрите на EfficientAdapter здесь ссылка

И объяснил больше об эффективном адаптере и методе getView в другом потоке, посмотрите на это, вот ссылка

Надеюсь, что это поможет !!!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...