- Android Architecture Components. Часть 2. Lifecycle
- Android курс в Технополисе 2019
- Custom View
- Жизненный цикл View
- Constructor
- onAttachedToWindow
- onMeasure
- onLayout
- onDraw
- Обновление View
- Иерархия
- Android View Lifecycle
- Hai Nguyen
- What is View?
- View Lifecycle
- Sign up for more like this.
- The Journey of A System
- Can’t run app on device when it installed from debug apk file
- Transforming a weird WordPress instance into a Ghost one
Android Architecture Components. Часть 2. Lifecycle
Как я уже упоминал в предыдущем материале, компонент Lifecycle призван упростить работу с жизненным циклом, а имено избежать калбеков с Activity/Fragment в наш компонент, который должен реагировать на события жизненого цикла. В этой статье, мы подробно разберем как он устроен и как с ним работать.
Сам компонент состоит из классов: Lifecycle, LifecycleActivity, LifecycleFragment, LifecycleService, ProcessLifecycleOwner, LifecycleRegistry. Интерфейсов: LifecycleOwner, LifecycleObserver, LifecycleRegistryOwner.
Lifecycle — класс, который хранит информацию про состояние жизненного цикла и разрешает другим объектам отслеживать его c помощью реализации LifecycleObserver. Состоит из методов: addObserver(LifecycleObserver), removeObserver(LifecycleObserver) и getCurrentState(). Как понятно из названий для добавления подписчика, удаления и соответственно получения текущего состояния.
Для описания состояния есть два enum. Первый Events — который обозначает изменение цикла и второй State — который описывает текущее состояние.
Events — повторяет стадии жизненного цикла и состоит из ON_CREATE, ON_RESUME, ON_START, ON_PAUSE, ON_STOP, ON_DESTROY, а также ON_ANY который информирует про изменения состояния без привязки к конкретному этапу. Отслеживание изменений цикла происходит с помощью пометки метода в обсервере аннотацией OnLifecycleEvent, которому как параметр передается интересуещее нас событие.
State — состоит из следующих констант: INITIALIZED, CREATED, STARTED, RESUMED, DESTROYED. Для получения состояния используеться метод getCurrentState() из Lifecycle. Также в Enum State реадизован метод itAtLeast(State), который отвечает на вопрос являтся State выше или равным от переданого как параметр.
Для работы с компонентом Lifecycle, нам нужно определить owner, то есть владельца жизненного цикла и observer, того кто на него будет подписан. У owner может быть любое количество подписчиков, также стоит отметить что observer будет проинформирован про изменение состояния, еще до того как у owner будет вызван метод super() на соответствующий метод жизненного цикла.
Owner должен реализовывать интерфейс LifecycleOwner, который содержит один метод getLifecycle(), который возвращает екземпляр класса холдера Lifecycle.
Observer должен реализовать интерфейс маркер LifecycleObserver.
Для самостоятельного обьявления кастомной Activity/Fragment, как owner-а, которые еще не поддерживают новый компонент и соответственно не имеют реализации Lifecycle, созданы: класс LifecycleRegistry и интерфейс LifecycleRegistryOwner.
Интерфейс LifecycleRegistryOwner, который в свою очередь расширяет интерфейс LifecycleOwner с единственым отличием в том что метод getLifecycle() возвращает LifecycleRegistry вместо Lifecycle.
Класс LifecycleRegistry, который являеться расширением Lifecycle и берет всю работу по поддержке на себя, нам лишь нужно создать его экземпляр.
Вот как выглядит реализация:
В пакете android.arch.lifecycle приведено 4 реализации owner: LifecycleActivity, LifecycleFragment, LifecycleService, ProcessLifecycleOwner.
LifecycleActivity — это FragmentActivity c реализацией LifecycleRegistryOwner. Является временным решением для упрощения работы и как сказано в документации будет пока Lifecycle не будет интегрирован с support library.
LifecycleFragment — это Fragment c пакета support.v4, который также как и в случае с LivecycleActivity реализовывает LifecycleRegistryOwner и является временным решением.
LifecycleService — это Service, который является также LifecycleOwner.
ProcessLifecycleOwner — это класс, который представляет Lifecycle всего процесса. Этот класс будет полезен если вам нужно отслеживать уход приложения в бэкграунд или возврат его на передний план.
Для того чтоб, связать owner и observer нужно у owner вызвать getLifecycle().addObserver(LifecycleObserver) Ниже я продемонстрирую работу всех этих классов. Для демонстрации, я создал класс SomeObserver, который будет логировать вызовы ON_CREATE и ON_STOP, я его буду использовать для всех видов owner-ов, поэтому для упрощения я добавил enum, константа с которого будет передаваться в конструктор и потом использоваться, чтоб отличить владельца по логам:
В целом же работа со всеми классами аналогичная, все что нам нужно это создать экземпляр обсервера и подписать его на Lifecycle, в моей реализации мы передаем наш Lifecycle в конструктор обсервера, подпиской занимаеться уже сам обсервер. Данный подход, является всего лишь делом вкуса и не более.
Листинг LifecycleService, он отрабатывает 5 секунд и завершается, его я запускаю из Application:
И для ProcessLifecycleOwner я решил расширить Application, как можно заметить ProcessLifecycleOwner сделан как singleton и являеться абсолютно самостоятельным компонентом:
Полный листинг вы можете посмотреть по линке: here
Также полезные ссылки: раз и два.
В следующей статье мы более подробно разберем LiveData компонент.
Источник
Android курс в Технополисе 2019
В этом уроке мы научимся создавать собственные View .
Custom View
Обычно термин Custom View обозначает View , которого нет в sdk Android. Или другими словами — это View которое мы сделали сами.
Когда может понадобиться реализация собственного View :
- специфичная отрисовка;
- специфичная обработка жестов;
- оптимизация существующих элементов;
- правка багов в существующем элементе.
Как правило, создание custom view можно избежать используя темы, различные параметры View , а иногда и лисенеры. Но, если все таки вам действительно нужно сделать что-то особенное, давайте разберемся как же это сделать.
Для начала, давайте вспомним о том, как выглядит иерархия базовых компонентов:
Все ui компоненты наследуются от View , а лейауты от ViewGroup . В свою очередь ViewGroup наследуется от View .
Прежде чем наследоваться от базового класса View посмотрите, может быть вам ближе функциональность уже какого-то существующего элемента. Например Button , это не написанный с нуля компонент, а наследник TextView .
Жизненный цикл View
Первостепенно давайте разберемся с жизненным циклом View .
Constructor
Каждый элемент начинает свое существование с конструктора. У View их целых четыре штуки:
Создание View из кода:
Создание View из XML:
Создание View из XML со стилем из темы:
Создание View из XML со стилем из темы и/или с ресурсом стиля:
Последний конструктор добавлен в sdk версии 21. Каждый из конструктор каскадно вызывает следующий.
onAttachedToWindow
После того как родитель View вызовет метод addView(View) , наш View будет прикреплён к окну. На этой стадии наш View-компонент попадает в иерархию родителя.
onMeasure
Этот метод означает, что наш View находится на стадии определения собственного размера. Для того что бы понять как распределить элементы на экране и сколько они занимают место нужно получить от каждого View его размер. В методе measure как раз и происходят расчеты.
Давайте посмотрим на сам метод:
Метод onMeasure() принимает 2 аргумента: widthMeasureSpec и heightMeasureSpec . Это значения, которые содержат в себе информацию о том, каким размером хочет видеть ваше View родительский элемент.
Каждое из значений на самом деле содержит 2 параметра:
- mode . Указывает на то, какие правила применяются ко второму параметру size;
- size . Непосредственно размер View .
Получить эти параметры можно при помощи методов класса MeasureSpec :
mode может принимать следующие значения:
- MeasureSpec.EXACTLY . Означает, что размер задан жёстко. Независимо от размера вашего View , вы должны установить определённую ширину и высоту;
- MeasureSpec.AT_MOST . Означает что View может быть любого размера, которого пожелает, но, не больше чем размер родителя. Это значение match_parent ;
- MeasureSpec.UNSPECIFIED . Означение что View может само решить какой размер ему нужен не взирая ни на какие ограничения. Это значение wrap_content .
В коде это можно описать следующим образом:
где wrapWidth , это наша желаемая ширина. Аналогичный подход применяется и к высоте View .
Конечно же не нужно каждый раз писать эту конструкцию из условий. Для упрощения работы у View есть метод
который уже включает в себя все необходимые условия.
После того как мы выполнили все расчеты, необходимо установить рассчитанные размеры при помощи метода:
Расчет размера можно разделить на 4 стадии:
- Родитель узнает “пожелания”, каким размером View хочет быть, определение LayoutParams наследника. Это может быть сделано как через xml, так и кодом:
- Родитель начинает измерять свои дочерние View и просит рассчитать их размеры.
- Дочерняя View рассчитывает свои размеры и устанавливает значение.
- Родитель сообщает о том, что расчет закончен и можно получить финальные значения.
onLayout
Этот метод позволяет присваивать позицию и размер дочерним элементам ViewGroup . В случае, если мы наследовались от View , нам не нужно переопределять этот метод.
onDraw
Это основной метод при разработки собственной View . В onDraw вы можете рисовать все что вам нужно. Метод имеет следующую сигнатуру:
На полученном Canvas вам требуется непосредственно изобразить саму View . Рисование на Canvas происходит при мощи объекта Paint . Paint отвечает за то, как именно будет отрисован контент вашего View и имеет множество параметров.
Стоит обратить внимание, что onDraw вызывается не один раз и может занимать много времени. Поэтому стоит максимально аккуратно работать с отрисовкой, не аллоцировать никаких объектов и не делать лишних операций.
Обновление View
Из диаграммы жизненного цикла видно, что существуют два метода, которые заставляют View перерисовываться:
invalidate() . Используется когда нужно только перерисовать ваш элемент. Когда изменился цвет или текст или нужно сделать какие-то еще визуальные изменения;
requestLayout() . Используется когда нужно изменить размеры вашего View . Вызов requestLayout не только заставит View заново измериться, но и перерисует элемент.
Иерархия
Вызовы всех методов View проходят от базового View к потомкам, сверху вниз.
Во время расчета размера View потомок принимает “пожелания” от родителя, рассчитывает свои размеры, а также размеры своих потомков. (Measure pass)
После того как размеры известны, родитель проставляет размеры и расположение своим потомкам. (Layout pass)
Последним этапом является отрисовка. Она также происходит от родителя к потомку
Источник
Android View Lifecycle
Hai Nguyen
[
In Android, View class is the base for widgets, which are used to create interactive UI components(Button, TextView, EditText,…). Android’s widgets are sufficient for the needs of most apps. However, there may be occasions on which you feel the need to implement a custom user interface for a project you are working on.
All of the view class defined in Android framework extend View. Our custom view can also extend View directly, or we can save time by extending one of the existing view subclasses, such as Button, TextView. We must understand View before we create a custom view.
What is View?
Same as above, View is the base class for widgets, which are used to create interactive UI components (buttons, text fields, etc.). The [ViewGroup](http://developer.android.com/reference/android/view/ViewGroup.html» target=»_blank»>) subclass is the base class for layouts, which are invisible containers that hold other Views (or other ViewGroups) and define their layout properties.
So, what about Android View lifecycle?
View Lifecycle
[
To implement a custom view, my custom view class must extend Android View class. My custom view will begin by providing overrides for some of standard methods that the framework calls on all views. You do not need to override all of these methods. In fact, you can start by just overrideing onDraw(android.graphics.Canvas)
Category | Methods | Description |
---|---|---|
Creation | Constructors | There is a form of the constructor that are called when the view is created from code and a form that is called when the view is inflated from a layout file. The second form should parse and apply any attributes defined in the layout file. |
`onFinishInflate()` | Called after a view and all of its children has been inflated from XML. | |
Layout | `onMeasure(int, int)` | Called to determine the size requirements for this view and all of its children. |
`onLayout(boolean, int, int, int, int)` | Called when this view should assign a size and position to all of its children. | |
`onSizeChanged(int, int, int, int)` | Called when the size of this view has changed. | |
Drawing | `onDraw(android.graphics.Canvas)` | Called when the view should render its content. |
Event processing | `onKeyDown(int, KeyEvent)` | Called when a new hardware key event occurs. |
`onKeyUp(int, KeyEvent)` | Called when a hardware key up event occurs. | |
`onTrackballEvent(MotionEvent)` | Called when a trackball motion event occurs. | |
`onTouchEvent(MotionEvent)` | Called when a touch screen motion event occurs. | |
Focus | `onFocusChanged(boolean, int, android.graphics.Rect)` | Called when the view gains or loses focus. |
`onWindowFocusChanged(boolean)` | Called when the window containing the view gains or loses focus. | |
Attaching | `onAttachedToWindow()` | Called when the view is attached to a window. |
`onDetachedFromWindow()` | Called when the view is detached from its window. | |
`onWindowVisibilityChanged(int)` | Called when the visibility of the window containing the view has changed. |
Sign up for more like this.
The Journey of A System
It has been a long time since my last blog, the world has seen lots of changes, including technology innovation, pandemic and especially the way we communicate with each other and with digital product. This post is brief to the journey for one of our product which we involved a
Can’t run app on device when it installed from debug apk file
It has been a long time since I last post, today I want to share for you an occurred problem recently when I start a new Android project. First, let us examine the outline what i do before find solution for problem. I create a new Android project with AndroidStudio
Transforming a weird WordPress instance into a Ghost one
Hello 2017, hope everyone will have an interesting year ahead. It has been a long time since last post of us, due to several personal stuffs. So today, I would like to come back, and with a very first news about CodenTrick: We have transformed our WordPress instance into a
Источник