Pull to refresh

Tips and Tricks по программированию на Android

Reading time 5 min
Views 7.2K
Tips and Tricks
Летом друг подкинул пару заказов по разработке для Android. Первое это streaming проигрыватель видео для одного французского телевидения, второе — простенькая игрушка.
Во время разработки (мой первый опыт разработки на Android и на Java), я уяснил несколько правил, которые нужно соблюдать для корректной и устойчивой работы программ, которыми хочу поделится…

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

Примеры


Для наглядности я создал небольшой проект, в котором приведено несколько примеров к правилам ниже.
Main Activity
Исходники: fileshare.in.ua/3050399
APK: fileshare.in.ua/3050402

Правило 1. Не выполняйте сложные операции в UI потоке


Not responding
Выполнение каких-либо сложных операция в UI потоке приведет к тому что UI будет недоступен пользователю (т. е. будет «висеть»). При этом любые действия пользователя, во время таких «подвисаний», могут привести к появлению сообщения о том что приложение зависло, с предложением закрыть его.
Поэтому все сложные вычисления стоит выносить в отдельный поток.

На примере:
Посмотреть как не нужно делать, и к чему это приводит можно нажав кнопку «Do all on UI thread». В момент нажатия, происходит создание дочернего Activity у которого в методе onCreate() стоит псевдо-сложная операция, которая занимает 20 секунд. После нажатия, при попытке нажать кнопку Back телефона, выскакивает сообщение о том что приложение «подвисло».
При нажатии кнопки «Do hard operation with separate thread» основного окна, произойдет создание Activity и потока для выполнения сложной операции.

Правило 2.Используйте адаптеры правильно


ListView
При работе с нестандартными списками, создание строк происходит по средствам скрытого вызова метода getView() адаптера, установленного для данного списка.
В getView() адаптера, разработчику предоставляется возможность создать строку любого вида. Например:
image

Пример:
Как не надо делать:
@Override
public View getView(int position, View convertView, ViewGroup parent) {
  final View view = mInflater.inflate(R.layout.row, null);

  TextView tv_programm = (TextView) view.findViewById(R.id.channel_proramm);
  TextView tv_starttime = (TextView) view.findViewById(R.id.time_start);
  TextView tv_endtime = (TextView) view.findViewById(R.id.time_end);
  ImageView ib_logo = (ImageView) view.findViewById(R.id.channel_logo);
  ProgressBar pb_progress = (ProgressBar) view.findViewById(R.id.programm_progress);

  tv_programm.setFocusable(false);
  tv_starttime.setFocusable(false);
  tv_endtime.setFocusable(false);
  ib_logo.setFocusable(false);
  pb_progress.setFocusable(false);

  ib_logo.setClickable(false);

  final String name = mNames[position];
  if ( name != null ) {
    tv_programm.setText(name);
  }
  return view;
}


* This source code was highlighted with Source Code Highlighter.

Тут для каждой строки списка вызывается создание нового объекта View. В результате, при перелистывании списка, мы получим засорение памяти объектами которые не отображаются. И следовательно Garbage Collector будет вызываться чаще (см. правило 3).

Как правильно делать:
private class ViewHolder {
  TextView tv_programm;
  TextView tv_starttime;
  TextView tv_endtime;
  ImageView ib_logo;
  ProgressBar pb_progress;
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {
  ViewHolder holder = null;
  if ( convertView == null ) {
    convertView = mInflater.inflate(R.layout.row, null);

    holder = new ViewHolder();
    holder.tv_programm = (TextView) convertView.findViewById(R.id.channel_proramm);
    holder.tv_starttime = (TextView) convertView.findViewById(R.id.time_start);
    holder.tv_endtime = (TextView) convertView.findViewById(R.id.time_end);
    holder.ib_logo = (ImageView) convertView.findViewById(R.id.channel_logo);
    holder.pb_progress = (ProgressBar) convertView.findViewById(R.id.programm_progress);

    holder.tv_programm.setFocusable(false);
    holder.tv_starttime.setFocusable(false);
    holder.tv_endtime.setFocusable(false);
    holder.ib_logo.setFocusable(false);
    holder.pb_progress.setFocusable(false);

    holder.ib_logo.setClickable(false);

    convertView.setTag(holder);
  } else {
    holder = (ViewHolder) convertView.getTag();
  }

  final String name = mNames[position];
  if ( name != null ) {
    holder.tv_programm.setText(name);
  }
  return convertView;
}


* This source code was highlighted with Source Code Highlighter.

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

В чем выигрыш?
В примере к правилу 2 (кнопки «Use incorrect list adapter» и «Use correct list adapter»), создается список из 1000 строк.
При запуске, приложения использует 3% общей памяти устройства.
При перелистывании списка с неправильным использованием адаптера, необходимо дополнительно 14% памяти устройства, что бы пролистать список до последнего элемента. При этом прорисовка происходит дерганно.
Если использовать адаптер правильно, дополнительно используется <=1% и перелистывание проходит плавно.

Правило 3. Поменьше выделений памяти (Java и Garbage Collector)


Это правило наверное знакомо каждому разработчику Java. Но т. к. я раньше программировал на C++, Garbage Collector (aka GC) был для меня в новинку.
Чем чаще происходит создание и удаление объектов, тем чаще вызывается GC. А каждый вызов GC занимает 100-200мс. При этом все потоки на время выполнения GC останавливаются. При этом прорисовка кадров может быть заметна (порой <10 fps).

Заключение:


Это только малая часть того что мне удалось почерпнуть, пока работал с Android, и если тема кому-то будет интересна, буду писать следующую порцию советов и трюков.

Полезные ссылки:


android-developers.blogspot.com — блог разработчиков Android
developer.android.com/videos/index.html — видео о разработке под Android
Особенно советую посмотреть:
Google I/O 2009 — Make your Android UI Fast and Efficient. — Правило 2 взято отсюда.
Google I/O 2009 — Writing Real-Time Games for Android. — Правило 3.

UPD: спасибо за карму, перенес в Android
UPD2: спасибо хабрапользователю i_home за еще одну полезную ссылку small-coding.blogspot.com в комментариях
Tags:
Hubs:
+59
Comments 44
Comments Comments 44

Articles