17 December 2009

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

Development for Android
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:androiddevelopment
Hubs: Development for Android
+59
4.2k 123
Comments 44