Best practices от Google по разработке Android приложений

В данной статье я хотел бы вкратце рассказать про самые последние best practices от Google. Я постарался выделить самые основные моменты, чтобы читатель сразу мог понять, что именно какая-либо фича дает разработчику. Не удивляйтесь, если где-то повторяюсь. Конспектировал + добавлял от себя по ходу просмотров видео в www.youtube.com/channel/UCVHFbqXqoYvEWM1Ddxl0QDg

Также к каждому пункту приводятся все необходимые ссылки для более подробного ознакомления с конкретной best practice.

Best practices. UI


1. Использование hardware accelaration. Позволяет улучшить плавность ui, анимации за счет предарительной отрисовки и хранения этих отрисовок в памяти (вместо динамической постоянной отрисовки и перерисовки)

2. Для кастомных View или анимаций (прозрачность и прочее), рекомендуется использовать hardware accelaration. Пример:

View.setLayerType(View.LAYER_TYPE_HARDWARE, null);
ObjectAnimator animator = ObjectAnimator.ofFloat(view, "rotationY", 180);
animator.addListener(new AnimatorListenerAdapter() {
    @Override
    public void onAnimationEnd(Animator animation) {
        view.setLayerType(View.LAYER_TYPE_NONE, null);
    }
});
animator.start();


3. В кастомной view, если метод переопределить метод hasOverlappingRendering и возвращать false, то view нельзя будет задавать альфу прочее, зато производительность в раза два поднимется.

Ссылка: www.youtube.com/watch?v=wIy8g8yNhNk&list=PLWz5rJ2EKKc9CBxr3BVjPTPoDPLdPIFCE&index=9
По этой ссылке — developer.android.com/guide/topics/graphics/hardware-accel.html — еще советы по оптимизации UI

4. В onDraw не рекомендуется создавать объекты (типа Paint и т.д.). Данные объекты можно сделать статическими — это экономия памяти + предварительное создание + отсутствие постоянного вызова gc.
Ссылка: www.youtube.com/watch?v=HAK5acHQ53E&index=10&list=PLWz5rJ2EKKc9CBxr3BVjPTPoDPLdPIFCE

5. Tools: Strict mode. Данная тулза настраивается в настройках разработчика на устройстве. Она позволяет отловить все потенциально узкие места в UI (что-то тормозит, где-то блокируется UI — ThreadPolicy). Также можно отловить memoty leaks (VMPolicy). Настроить режим для приложения можно через соответствующий класс — developer.android.com/reference/android/os/StrictMode.html

6. При создании custom view.
View.invalidate() — вызывает перерисовку элемента. Это зло. Если что-то поменялось, то нужно перерисовывать не весь view, а конкретный Rect (если он видим пользователю).

Не рисовать лишнее. Что не видно, то не рисовать. Банально, но часто этим пренебрегают. Canvas.clipRect() в помощь. Также для быстрого определения, что слой не видим — Canvas.quickReject(...)

Не перегружать слишком в угоду другому CPU и GPU.

Ссылка:https://www.youtube.com/watch?v=zK2i7ivzK7M&list=PLWz5rJ2EKKc9CBxr3BVjPTPoDPLdPIFCE&index=12

7. Bitmap. Желательно подгружать предварительно сжатые картинки с помощью BitmapFactory.Options
developer.android.com/training/displaying-bitmaps/load-bitmap.html

8. Bitmap. При создании Bitmap из картинки (jpeg, png) по умолчанию используется формат ARGB_8888 (32 бита на пиксель). Если критичен вопрос памяти, можно использовать другие форматы (RGB_565 — 16 бит и другие). Выставление данного параметра происходит через BitmapOptions. Конвертация, конечно же, сказывается на производительности.

Ссылка: www.youtube.com/watch?v=1WqcEHXRWpM&list=PLWz5rJ2EKKc9CBxr3BVjPTPoDPLdPIFCE&index=14

9. www.youtube.com/watch?v=2TUvmlGoDrw&list=PLWz5rJ2EKKc9CBxr3BVjPTPoDPLdPIFCE&index=15 — разные форматы картинок
новый гугловский формат (качество то же, размер меньше) — developers.google.com/speed/webp/?csw=1

10. Масштабирование в BitmapOptions для экономии памяти при загрузке картинок с высоким разрешением
www.youtube.com/watch?v=HY9aaXHx8yA&index=16&list=PLWz5rJ2EKKc9CBxr3BVjPTPoDPLdPIFCE
developer.android.com/training/displaying-bitmaps/load-bitmap.html#load-bitmap

11. Overdraw. Заставляет GPU работать вхолостую (рисование скрутытх элементов). Для определения overdraw, нужно в DeveloperOptions включить Show GPU Overdraw flag. Также помогает тулза ViewHierarchy.

Ссылка: www.youtube.com/watch?v=T52v50r-JfE&list=PLWz5rJ2EKKc9CBxr3BVjPTPoDPLdPIFCE&index=22

12. TraceView также хорошо подходит для определения корректности отрисовки. Все отрисовки должны помещаться в 16 мс (60 кадров в секунду).

Ссылка: www.youtube.com/watch?v=HXQhu6qfTVU&index=21&list=PLWz5rJ2EKKc9CBxr3BVjPTPoDPLdPIFCE

13. VSYNC. Что это такое.
Refresh rate (60 hz) — это частота обновления экрана, константа. Frame rate — частота обновления фрейма в секунду. Единица измерения GPU.

Обе скорости должны быть синхронизированы для корректного отображения. Для решения данной проблемы используется двойная буферизация. С GPU картинки идут в back buffer, а затем в frame buffer, а оттуда на экран. Между back buffer и frame buffer находится VSYNC, который следит за тем, чтобы данные с back buffer переходили в frame buffer синхронно скорости обновления экрана. Это устраняет возможные коллизии картинки на экране.

Скорость работы GPU (frame rate) должна быть выше скорости обновления экрана (refresh rate) для того, чтобы ui был плавным.
www.youtube.com/watch?v=1iaHxmfZGGc&index=23&list=PLWz5rJ2EKKc9CBxr3BVjPTPoDPLdPIFCE

14. Tool — Profile GPU Rendering
Подключить можно в DeveloperOptions. Нам интересен граф для приложения. Есть еще для навигации и notification bar. Сам график представляет собой совокупность времен, требуемых на прорисовку frame. График не должен превышать зеленую вертикальную линию — 16ms (скорость обновления экрана).

Состав графика хорошо описан в видео ниже. Все довольно понятно:
www.youtube.com/watch?v=VzYkVL1n4M8&index=24&list=PLWz5rJ2EKKc9CBxr3BVjPTPoDPLdPIFCE

15. Работа CPU и GPU на русском хорошо расписана в www.youtube.com/watch?v=zVK6TKSx1lU&feature=iv&src_vid=VzYkVL1n4M8&annotation_id=annotation_3064896115
Критично для игр)

16. Почему мы должны придерживаться скорость 60 fps — www.youtube.com/watch?v=CaMTIgxCSqU&index=25&list=PLWz5rJ2EKKc9CBxr3BVjPTPoDPLdPIFCE

17. Android UI and the GPU
GPU нужен для растеризации полигонов, текстур. CPU отдает GPU необходимые графические элементы и с помощью OpenGL эти элементы конвертируются в полигоны и текстуры и хранятся в GPU (нужно уточнить?). Плюс другие оптимизации GPU: отрисовка не всего экрана, а изменяемых частей, объединение элементов в полигоны и т.д.:
www.youtube.com/watch?v=WH9AFhgwmDw&list=PLWz5rJ2EKKc9CBxr3BVjPTPoDPLdPIFCE&index=26

18. Show GPU view updates in DevOps — показывает, какие элементы invalidate()

Best practices. Коллекции


1. По default для перебора всех элементов коллекции рекомендуется использовать Итератор.
Но в критических ситуациях встает вопрос выбора самого быстрого способа перебора. Самые лучшие показатели принадлежат ArrayList с перебором по индексу.
Ссылки: developer.android.com/training/articles/perf-tips.html#Loops, www.youtube.com/watch?v=MZOf3pOAM6A&list=PLWz5rJ2EKKc9CBxr3BVjPTPoDPLdPIFCE&index=6

Best practices. Способы синхронизации. Энергосберегающие


1. JobScheduler + github.com/evant/JobSchedulerCompat (для версий < 21). Средство, формирующее очередь для фоновых операций (особенно работа с сетью), и организующее их выполнение равными кусками для эффективного энергосбережения батареи (радио пребывает в активном и выжидающем режиме малое количество времени). Для задач мы задаем условия, когда, с какой периодичностью, при каком соединении и т.д. они должны запускаться.

2. SyncAdapter. Старое решение. Много кода + собственный ContentProvider.

3. GCM. Как замена JobScheduler — developers.google.com/cloud-messaging/network-manager. Позволяет производить синхронизацию не путем периодического опроса сервиса, а получением от GSM сообщения об изменении чего-то в сервисе, собственно, необходимо обновиться и клиенту. Плюс только сообщения GSM будут доходить до устройства в режиме глубокого сна (M version)

4. Firebase Offline. Оффлайн синхронизация.

5. AlarmManager. Задается два типа времени запуска/повтора: inexact (время коррелируется с временем запуска других приложений для экономии батарейки, рекомендуется), exact (точное время, не рекомендуется)

Best practices. Battery


1. Для отслеживания работы батареи в приложении можно использовать:
— Настройки приложения
— battery-historian (https://github.com/google/battery-historian)

Для экономии батареи с случаях, когда необходимо делать какие-либо периодические запросы, рекомендуется — JobScheduler
Куда уходит батарея — research.microsoft.com/en-us/people/mzh/eurosys-2012.pdf Хороший research:
www.youtube.com/watch?v=9i1_PnPpd3g&index=29&list=PLWz5rJ2EKKc9CBxr3BVjPTPoDPLdPIFCE

Best practices. Память


1. Object pools ( www.youtube.com/watch?v=bSOREVMEFnM&index=5&list=PLWz5rJ2EKKc9CBxr3BVjPTPoDPLdPIFCE ). Для самостоятельного контроля над памятью, выделяемой для тяжеловесных объектов (типа Bitmap и прочее). Необходимо для того, чтобы контролировать, когда должен срабатывать GC — скорость и плавность работы приложения.
Возможные решения: LRUCache, Pools (https://developer.android.com/reference/android/support/v4/util/Pools.html), FlatBuffers (https://google.github.io/flatbuffers/ )

2. Думаю, обычного LRUCache вполне должно хватить

Best practices. GC


1. Сравнение Dalvik and ART — source.android.com/devices/tech/dalvik
Как пример, у ART улучшенная работа GC благодаря, в том числе, и параллелизации работы GC:
www.youtube.com/watch?v=pzfzz50W5Uo&list=PLWz5rJ2EKKc9CBxr3BVjPTPoDPLdPIFCE&index=34

Google play services 7.5


1. Cloud messaging. Отправка сообщений с определенными темами, NetworkManager, повторяющий в принципе JobScheduler
developers.google.com/cloud-messaging

2. App invites. Приглашение от друга
developers.google.com/app-invites

3. Smart lock for passwords. Если юзер под своим аккаунтом на мобиле, и, к примеру, он заходил на приложение с браузера и сохранял пароль, то в приложении аутенфикация проходит автоматически: developers.google.com/identity/smartlock-passwords/android

Про эти нововведения и остальные здесь — developers.google.com/app-invites

Voice interaction


Управление приложением через голосовые команды. По ходу только с M версии.

io2015codelabs.appspot.com/codelabs/voice-interaction#1
developers.google.com/voice-actions

Новое и интересное


1. Fingerprint API (по пальцу) и Confirm credential(криптографически)
www.youtube.com/watch?v=VOn7VrTRlA4&index=11&list=PLOU2XLYxmsIJDPXCTt5TLDu67271PruEk
2. В M version в Настройках можно просмотреть, сколько приложение потребляет трафика и т.д.
3. Data binding в будущем (задание списка и даты прямо в xml)
4. RecyclerView ItemTouchHelper — Swipe-to-dismiss, Drag&Drop
5. При setAlpha hardware будет подключаться автоматически

Просто интересное


1. External storage — no hard code! Никогда не используйте при задании пути к файлу строчек типа — "/sdcard/" (то есть не задавайте путь до файлу вручную). Для этого есть специальные методы типа «Environment.getExternalStorageDirectory().getAbsolutePath()», которые всегда вернут вам корректный путь до файла, что не гаранировано при ручном задании.

Android studio


1. Поддержка SVG формата
2. Новый компилятор Jack
3. PNG Cruncher?
4. Coming: aapt
5. Studio 1.3 + Gradle 2.4 = большой прирост в скорости сборки
6. Data binding экспериментально доступен сейчас
7. Coming soon: Cloud test Lab, Google play testing
8. NDK support
9. Новые аннотации (WorkThread и т.д.)
10. Android Typed Integer — теперь будет видно, что какой-либо флаг означает
11. Capture view: Heap snapshot, Allocation tracking и т.д. — позволяет просматривать утечки памяти и прочее
12. Простое подключение гугловских сервисов (аналитика, облако и т.д.)
13. Theme editor
www.youtube.com/watch?v=f7ihSQ44WO0

Интересные библиотеки


1. Libraries for developers. Много интересных UI решений

Заключение


Надеюсь, статья вам понравится и будет интересна! Это моя первая статья, поэтому в случае получения вами положительных эмоций и знаний, жду инвайта. Если есть что добавить, либо поправить, жду комментов.
Поделиться публикацией
Похожие публикации
Реклама помогает поддерживать и развивать наши сервисы

Подробнее
Реклама
Комментарии 18
  • +16
    «скрутытх»

    Мне бы статья очень понравилась, если бы вместо пучка ютубов был пучок текстовых статей. Искренне не понимаю, как можно тратить пол дня на просмотр видюшек, когда всю ту же информацию можно было прочитать за пол часа. Или я просто читаю быстрее, чем смотрю…
    • +6
      Вы знаете, я с Вами полностью согласен. Для нас, для кого английский не родной, текстовая информация воспринимается гораздо быстрее и лучше. А главное, всегда можно вернуться и посмотреть еще раз.
      Но, увы, Google выкладывает свои Best practices в виде видео. И мне пришлось потратить гораздо больше, чем полня, на просмотр, учитывая, что у некоторых спикеров тяжкое произношение)
      Поэтому собственно и появилась идея сделать набор кратких тезисов. И если читатель заинтересуется и захочет более глубоко понять тему, он сможет сам просмотреть указанные ссылки)
      • +14
        Да это не совсем к вам претензия, а ко всем этим спикерам. Каждый второй бежит делать канальчик на ютубе, насмотревшись на примеры Гуглов и прочих. С ужасом жду того дня, когда документация по Google API и MSDN будет в виде видеороликов. Маркетологи портят мой интернет.) Ролики нужны для презентаций и демонстраций. Всё, точка. А когда начинающие программисты ищут видеоуроки по С++, у меня аж где-то что-то сжимается и начинает пригорать…
    • 0
      1. Использование hardware accelaration. Позволяет улучшить плавность ui, анимации за счет предарительной отрисовки и хранения этих отрисовок в памяти (вместо динамической постоянной отрисовки и перерисовки)

      Так и не разобрался как включается это ускорение. Обычная View.isHardwareAccelerated() всегда возвращает false. Как бы ты не прописывал это ускорение, я пробовал в манифесте
      <application
              android:hardwareAccelerated="true"
      
      и в самом окне
      public void onCreate(Bundle savedInstanceState) {
              super.onCreate(savedInstanceState);
              getWindow().setFlags(
                      WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED,
                      WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED);
      
      • 0
        У Гугла написано, что hardware accelaration для всех стандартных view включен по-умолчанию. Собственно ничего дополнительно выставлять не нужно)
        Если же Вы делаете какую-нибудь кастомную view, или Вам нужно применить к элементу анимацию, то как раз применяете данный код:
        View.setLayerType(View.LAYER_TYPE_HARDWARE, null);
        ObjectAnimator animator = ObjectAnimator.ofFloat(view, "rotationY", 180);
        animator.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                view.setLayerType(View.LAYER_TYPE_NONE, null);
            }
        });
        animator.start();
        

        Но в чем соль, как я понял. Посмотрим на вышеприведенный пример. Вы выставляете hardware accelaration перед анимацией:
        View.setLayerType(View.LAYER_TYPE_HARDWARE, null)
        , а после анимации снимаете данный флаг:
         View.setLayerType(View.LAYER_TYPE_NONE, null) 
        .
        То есть перед началом анимации Вы для данной view подключаете использование GPU, оптимизирующее прорисовку элемента. После завершения GPU для данной view не нужен, поэтому мы снимаем флаг hardware acceleration.
        Соственно и поэтому View.isHardwareAccelerated() всегда возвращает false. Во время выполнения анимации по идее должен тогда возвращать true.
        Я могу ошибаться, поэтому поправьте меня. Если честно, данная тема не очень хорошо и подробно раскрыта Гуглом. Скорее всего полный анализ hardware accelaration и создания качественный кастомных view рассмотрен в данном видео 2013 года еще — www.youtube.com/watch?v=NYtB6mlu7vA
        Но у меня еще не дошли руки с этим видео и вообще вопросом качественно разобраться :)
        • 0
          У Гугла написано, что hardware accelaration для всех стандартных view включен по-умолчанию.

          Тогда почему эти самые View возвращают false?
          Там вообще как я понял, работать ускорение должно с 11 по 14 апи.
          • 0
            Немножко не ясно ответил я. В обычных ситуациях вьюшкам hardware acceleration не нужен. Только если появляется у этого элемента анимация, прозрачность (кстати прозрачность — это большое зло для производительности UI, как говорит Гугл), включается для них hardware acceleration. Анимация закончилась — hardware acceleration отключается, чтобы разгрузить GPU.
            Но еще раз говорю, я тут могу ошибаться, так как тему еще не полностью изучил.
      • +1
        Что-то я не понял, из чего вы сделали вывод про
        Если имеем обычный массив, то лучше перевести его в ArrayList, а затем весь перебрать.

        ?
        В совете на Android Developers говорится совсем о другом:
        — для обычных массивов стоит использовать «enhanced for» (ф-ия two() в их примере)
        — для ArrayList самым быстрым является вариант с «оптимизированным» for (ф-ия one()), и видео тоже это подтверждает
        Но никто нигде не упоминал, что массивы надо конвертировать в ArrayList.
        • 0
          Точно! Я почему-то перепутал Vector с массивом, хотя вроде во время просмотра математику вроде не читал…
          Спасибо Вам большое! Подправлю!
        • +1
          6. External storage — no hard code!

          Подскажите, что тут имеется ввиду. Нет внешней памяти или нет проблемам с внешним хранилищем (получение пути, установка на внешнюю флешку и т.п.)?

          В целом статья вышла полезной, спасибо.
          • 0
            Это было бы слишком жестко)
            Приведу пример того, что имел в виду
            При создании файла мы можем использовать такой код:
            myFile = new File("/sdcard/" + txtName.getText() + ".txt");
            

            где путь к директории, в которой должен храниться файл, задается вручную.
            А нужно использовать такой код:
            myFile = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/"+ txtName.getText() + ".txt");
            

            где путь к директории задается через специально предназначенный для этого метод Environment.getExternalStorageDirectory().getAbsolutePath()
            • 0
              Так это всегда так было. Этот метод доступен с первой версии андроида. Пруф
              • 0
                Так никто и не спорит) Но очень распространены случаи, когда пути к директориям прописывают вручную.
                • +1
                  Сами себе злобные буратинки. Никакой гарантии что этот путь валидный нет.
                  • 0
                    Так вы пишете этот пункт под заголовком «Новое и интересное» =)
                    • 0
                      Ааа, точно) согласен, это не относится к категории «Новое».
                      Спасибо за замечание)
            • –1
              Лучше-бы сперва время работы нормальное сделали на батарейке :( 5 версия вообще никуда :(
              • 0
                Вообще не заметил связи с вашим комментарием и постом.

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