April 21, 2020

Android Architecture Components. Часть 2. Lifecycle

Как я уже упоминал в предыдущем материале, компонент Lifecycle призван упростить работу с жизненным циклом, а именно избежать коллбеков с Activity/Fragment в наш компонент, который должен реагировать на события жизненного цикла. В этой статье мы подробно разберем, как он устроен и как с ним работать.

Примечание: данный цикл статей был написан летом 2017 года, поэтому некоторая информация может быть немного устаревшей, но общая концепция архитектурных компонентов с тех пор не изменилась.

Сам компонент состоит из классов: 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, которому как параметр передается интересующее нас событие.

@OnLifecycleEvent(Lifecycle.Event.ON_ANY)
void stateUpdated() {
    //будет вызваться при каждом изменении состояния жизненного цикла у оунера
}

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 и берет всю работу по поддержке на себя, нам лишь нужно создать его экземпляр.

Вот как выглядит реализация:

class MyFragment : Fragment(), LifecycleRegistryOwner {

    val lifecycleRegistry = LifecycleRegistry(this)

    override fun getLifecycle(): LifecycleRegistry {
        return lifecycleRegistry
    }
}

В пакете 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, константа с которого будет передаваться в конструктор и потом использоваться, чтобы отличить владельца по логам:

class SomeObserver(
    lifecycle: Lifecycle,
    private val owner: Owner
) : LifecycleObserver {

    @OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
    fun onCreate() {
        Log.d(«Observer», owner + «: onCreate»)
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_STOP)
    fun onStop() {
        Log.d(«Observer», owner + «: onStop»)
    }

    enum Owner {
        ACTIVITY, FRAGMENT, PROCESS, SERVICE
    }
}

В целом же работа со всеми классами аналогичная. Все, что нам нужно, это создать экземпляр обсервера и подписать его на Lifecycle. В моей реализации мы передаем наш Lifecycle в конструктор обсервера, подпиской занимается уже сам обсервер. Данный подход является всего лишь делом вкуса и не более.

Листинг LifecycleActivity:

class MainActivity : LifecycleActivity() {

    val someObserver = SomeObserver(getLifecycle(), SomeObserver.Owner.ACTIVITY)

    override fun onCreate(savedInstanceState: Bundle) {
        super.onCreate(savedInstanceState)
        Log.d(«Owner», «onCreate»)
        setContentView(R.layout.activity_main)
    }

    override fun onStop() {
        super.onStop()
        Log.d(«Owner», «onStop»)
    }
}

Листинг LifecycleFragment:

class MyFragment : LifecycleFragment() {

   val someObserver = SomeObserver(getLifecycle(), SomeObserver.Owner.FRAGMENT)
  
   override onCreateView(
       inflater: LayoutInflater,
       container: ViewGroup,
       savedInstanceState: Bundle
   ): View {
      return inflater.inflate(R.layout.fragment_my, container, false)
   }
}

Листинг LifecycleService, он отрабатывает 5 секунд и завершается, его я запускаю из Application:

class MyService : LifecycleService() {

    lateinit val someObserver: SomeObserver

    override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
        someObserver = SomeObserver(getLifecycle(), SomeObserver.Owner.SERVICE)
        Handler().postDelayed(Runnable {
            stopSelf()
        }, 5000)
        return super.onStartCommand(intent, flags, startId)
    }
}

И для ProcessLifecycleOwner я решил расширить Application. Как можно заметить, ProcessLifecycleOwner сделан как singleton и является абсолютно самостоятельным компонентом:

class CustomApplication : Application() {

    private lateinit var processObserver: SomeObserver

    override fun onCreate() {
        super.onCreate()
        processObserver = SomeObserver(ProcessLifecycleOwner.getLifecycle(), SomeObserver.Owner.PROCESS)
        val intent = Intent(this, MyService::class.java)
        startService(intent)
    }
}

Полный листинг вы можете посмотреть здесь. Также полезные ссылки: раз и два.

В следующей статье мы более подробно разберем LiveData компонент.

Android Architecture Components. Часть 1. Введение

Android Architecture Components. Часть 3. LiveData

Источник: Android Architecture Components. Часть 2. Lifecycle