Tips and Tricks по программированию на 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 в комментариях
    AdBlock похитил этот баннер, но баннеры не зубы — отрастут

    Подробнее
    Реклама

    Комментарии 44

    • НЛО прилетело и опубликовало эту надпись здесь
        +2
        >> Во время разработки (мой первый опыт разработки на Android и на Java)
        Т.е. вы беретесь за коммерческий заказ, но при этом это ваш первый опыт на Java и Android? Круто. Вот он, суровый русский фриланс.

        Заказчик точно в курсе этого был?
          +14
          понимаю негодование, но не вижу ничего особенно «сурового»
          3 года профессионального программирования в крупной компании на С++ (непрофессиональной еще больше), опыт программирования под Symbian, знание шаблонов проектирования и технологий требуемых для проекта… что еще нужно?
          да, сознаюсь, поначалу очень сильно плевался на Java. много из С++ не хватало, но проект то я сдал вовремя ;)

          P. S. да, и заказчик был предупрежден о возможных заминках, по незнанию платформы.
            +1
            Ну если заказчик предупрежден, тогда окэ.
            Из того, что вы перечислили, неохваченным осталось знание платформы и особенностей managed environment, но если на плюсах писали, то должно пойти хорошо (правда, у меня от симбианских плюсов смешанные ощущения остались:)

            P.S. Негодования нет, это интерес под него прикинулся :)
              0
              имхо, после симбиана там все только радовать должно ))
              0
              Совершено нормальная ситуация, лишь бы исполнитель имел опыт программирования вообще, и был уверен, что все выполнит в срок. Это то же самое, как например, устраиваясь работать питонщиком, обнаруживаешь, что для работы придется изучить еще и яву. Тут то же самое, только это фриланс и ты осознанно идешь на изучение нового языка. По большому счету, для адаптации к любому высокоуровнему языку нужно не больше дня-двух, если вы, конечно, занимались программированием ранее.
                +1
                >> и был уверен, что все выполнит в срок

                На этих словах сполз под стол. Я думаю, что эта причина — первая по количеству провалов проектов и затягивания бюджетов.

                Я понимаю, вы, может, сам фрилансер, и защищаете собрата по цеху, но из вашего комментария (как он есть) выходит, что хороший писатель драйверов под AS/400 через пару дней будет с легкостью делать сайты. Бугага.
                А расскажите, что вы писали такого большого на java, чтобы быть уверенным, что осилите ее за 1-2 дня? :)
                  0
                  да какая разница на чем программировать, если умеешь программировать?.. ну што вы, ей богу.
                    –1
                    :)
                    –1
                    Сайты — это не только программирование, поэтому пример плохой.

                    Я не писал на java, если мне потребуется по работе написать приложение для андроида (а мне понадобиться через полгода, если все будет нормально), то я просто сяду и напишу.
                      +1
                      Ок, я понял; вероятно, и вправду пример не совсем.
                      А давайте его усилим: развернем условие в обратную сторону и точно выбросим непрограммистскую работу сайта; т.е. моя лемма такая: «программист бэк-ендов сайта через 2 дня не сможет писать драйвера».
                      Желаете оспорить?
                        0
                        Я не желаю это оспаривать. Ваша задача — победить в споре. Сделать это легко, подобрав слишком яркий аргумент, которому в жизни обычно не место.
                          0
                          Нет, у меня нет цели кого-то обыграть.

                          Я там ниже написал про SLA и SRS. «Я просто сяду и напишу» заканчивается как раз в тот момент, когда заканчивается хобби-стайл и начинается работа на результат. «Сесть и написать» плохо вписывается в режим «100% такого-то функционала надо к такому-то числу, хоть убейся. Не 95, а 100».

                          Если вы когда-нибудь будете писать mission-critical software, вы поймете, что я вам толкую.
                            0
                            Да я и так понимаю, о чем вы говорите :) Я лишь пытаюсь, сказать что нет ничего такого в том, что человек берется выполнять заказ, ни разу не сталкиваясь ранее с платформой.

                            Оценить сложности можно заранее и без изучения языка (зачастую, хотя и не всегда). Совершенно очевидно, что я, будучи флешером/питонщиком не сяду писать драйвера, но если мне понадобятся деньги и нужно будет, скажем, написать что-то на ненавистном мне Руби, то я напишу.
                              0
                              С явой, кстати, аналогично — ибо AS, Java, да даже яваскрипт — все на одном стандарте основаны. И во многом похожи, хотя далеко не во всем.
                                0
                                Это вы как flash-программист считаете, что AS и Java — одна малина :) Я не помню, чтобы Java была стандартизована по Ecma, например — подскажете ecma-номер?

                                Javascript и as3 куда ближе друг к другу, и одинаково далеки от Java.

                                И пересесть с javascript на java будет достаточно тяжело. Я бы, например, javascript-программиста вообще держал подальше от серьезных проектов первые год-полтора его опытов с java. Один java classpath и работу с нормальной серверной vm в голове уложить чего стоит, после браузерных-то велосипедов.
                                  0
                                  Насчет java -> javascript соглашусь по большей части. as3 от js уже дальше, чем вторая версия :) Намного.
                                0
                                >> нет ничего такого в том, что человек берется выполнять заказ, ни разу не сталкиваясь ранее с платформой.

                                Вот с этим я и спорю. Понятно, что надо как-то осваивать новое, куда без этого.

                                Но я бы не хотел оказаться в роли заказчика в таком случае — люди разные бывают: кто-то как исполнитель найдет в себе силы и посидит пару лишних ночей, чтобы разобраться с чертями в программе, а кто-то скажет «все, идите нахер, я сделал как смог, плати денех». Или вообще бросит на пол-дороги, ибо ниасилел; и хрен с ними, с деньгами — главное, время упущено. Я не согласен, что заказчик должен оплачивать эти риски.
                        0
                        Ну вот, к примеру, я никогда не писал ничего на java (кроме нескольких хелловорлдов в студенческие годы), но 7 лет писал на C++ (это если брать только коммерческий опыт, без учёта студенческого), но буквально на прошлой неделе за 3 вечера налабал «Пятнашки» для Blackberry. С тредами, сохранением таблицы рекордов на флэш-диск и прочими прелестями. Слегка подправить графику (дизайн делался «чтобы был», хотя тоже с градиентиками :)) — и можно хоть на продажу.
                        Не нужно думать, что для того, чтобы начать писать на каком-то языке, нужно обязательно полугодовые курсы заканчивать. А особенно если речь идёт о «ближайшем родственнике».
                          0
                          Вы правы, у меня подобный опыт тоже имеется :) Тут с вами не поспоришь. Однако вы не мою оригинальную мысль оспариваете.

                          Оригинальная была такова: как только у вас есть SRS и SLA, разработка в режиме «пятнашки just4fun» плохо вписывается в означенное условие. Другими словами, в ряду слов «фиксированный бюджет», «фиксированные сроки», «фиксированные требования» и «два самосвала граблей, заботливо разложенных во тьме неизвестной платформы» одно из слов явно лишнее. Моя мысль, что последнее, до тех пор, пока заказчик не согласен на некоторый R&D за его деньги (потому что сидеть ночами и разбираться, почему, например на flash при записи 20 мегабайт портится пару байт в середине — реальная, кстати, ситуация — желания нет совершенно). Поэтому я и уточнил, в курсе ли заказчик.

                          Пример SLA для проекта автора поста: FPS > 15 по всей программе (не хотят же пользователи смотреть слайдшоу)
                    0
                    1) тогда уж следовало бы рассказать и про AsyncTask, или вы сами не в курсе? ;)
                    3) для server-side не так заметно (я бы даже сказал, что в большинстве случаев практически незаметно) — в десктопной java GC работает значительно лучше.
                      0
                      1) честно, AsyncTask, использовал лишь раз. многое делал через потоки, — привычка ;)
                      3) как я указывал, не было опыта писать на Java особенно Java EE, но для Android в realtime играх GC — очень страшная вещь :)
                      0
                      Я когда-то пробовал реализовывать список, для элементов которого картинки подгружались в отдельных потоках. Наверное, я делал это неправильно, так как ничего не получилось. Как-нибудь попробую повторить с учетом данной статьи.
                        +1
                        если есть желание могу выслать пример, как можно подгружать изображения в список отдельными потоками ;)
                          0
                          Было бы здорово, спасибо.
                          tro.orl@gmail.com
                            0
                            ждите завтра…
                            сейчас нужно успеть доехать домой, пока пробок на дорогах меньше :)
                              0
                              И мне, плз, asdonair@gmail
                            0
                            Если не затруднит lazutkin@gmail.com
                              +3
                              Много желающих, и я к ним присоединяюсь.
                              Может пост на эту тему сделаете?
                                0
                                Присоединяюсь к просьбе сделать отдельный пост.
                                  0
                                  ок. сделаю пост в ближайшем будущем
                          • НЛО прилетело и опубликовало эту надпись здесь
                              0
                              Нет рейтинга проголосовать, поэтому просто напишу — Спасибо :)
                                +1
                                Спасибо. Именно такие статьи хочется видеть в блоге Android.
                                • НЛО прилетело и опубликовало эту надпись здесь
                                    0
                                    Я в ситуации с листом использовал свой класс, перегруженный от view.

                                    При разработке под андроид много чего интересного, необычного, неочевидного…
                                    Однако потом начинаешь скучать по этому.
                                    Я сейчас по WM скучаю по дизайнеру в эклипсе :)
                                      0
                                      По поводу упомянутой выше загрузке картинок в список отдельным потоков, у меня они еще и из сети получаются.
                                      Понятное дело, что при прокрутке необходимо выводить болванки, а при загрузке картинки менять ее на реальную. Ну и необходимо отследить, чтобы в один элемент не грузилось несколько картинок.
                                        0
                                        у меня несколько проще решение, с использованием стандартного ListView и ArrayAdapter.
                                        демо-проект уже сделал. осталось оформить его в статью. завтра, надеюсь, выложу.
                                          0
                                          С удовольствием почитаю :)
                                      • НЛО прилетело и опубликовало эту надпись здесь
                                          0
                                          я предупреждал, что для профессионалов статья интереса не несет ;)
                                          да и на «ноу-хау» я не претендую, посмотрите хотя бы блок «полезные ссылки», где я чесно сознаюсь откуда взял правила 2 и 3. 1е же, — это собственные грабли на которые наступал в начале изучения платформы.

                                          я бы с удовольствием почитал статьи о Вашем опыте программирования под Андроид, ведь он у Вас велик! поделитесь, пожалуйста, с Хабрасообществом :)
                                          • НЛО прилетело и опубликовало эту надпись здесь
                                          +2
                                          Тем кого интересует разработка под андроид могу посоветовать этот блог http://small-coding.blogspot.com/, там периодически публикуются советы по темам которые как правило плохо освещены в документации.
                                          Блог достаточно молодой но у него уже есть свои постоянные читатели.

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

                                          Самое читаемое