You are on page 1of 120

Android

Developers

Componentes de
Arquitectura

MCT: Luis Dueñas


Index
2. Componentes de Arquitectura
2.1. Android Architecture Components
2.2. Adding Components to your Project
2.3. Data Binding Library
2.3.1. Biblioteca de vinculación de datos
2.3.2. Get started
2.3.3. Layouts and binding expressions
2.3.4. Work with observable data objects
2.3.5. Generated binding classes
2.3.6. Binding adapters
2.3.7. Bind layout views to Architecture Components
2.3.8. Two way data binding
2.4. Handling Lifecycles with Lifecycle Aware Components
2.5. LiveData Overview
2.6. Paging Library
2.6.1. Paging library overview
2.6.2. Paging library UI components and considerations
2.6.3. Paging library data components and considerations
2.7. Room Persistence Library
2.8. ViewModel Overview
2.9. WorkManager
2.9.1. Schedule tasks with WorkManager
2.9.2. WorkManager basics
2.9.3. Advanced WorkManager topics
2.10. Saving UI States
Android Architecture Components   
Part of Android Jetpack ().

Android architecture components are a collection of libraries that help you design robust,
testable, and maintainable apps. Start with classes for managing your UI component
lifecycle and handling data persistence.

Manage your app's lifecycle with ease. New lifecycle-aware components () help you
manage your activity and fragment lifecycles. Survive con guration changes, avoid
memory leaks and easily load data into your UI.

Use LiveData () to build data objects that notify views when the underlying database
changes.
ViewModel () Stores UI-related data that isn't destroyed on app rotations.

Room () is an a SQLite object mapping library. Use it to Avoid boilerplate code and
easily convert SQLite table data to Java objects. Room provides compile time checks
of SQLite statements and can return RxJava, Flowable and LiveData observables.

Latest news and videos


 ()  ()  ()

VIDEO VIDEO ViewModels and


LiveData:
Improve your Build an App with Patterns +
App's Architecture AntiPatterns
Architecture Components
 ()
 ()  ()
Some do's and dont's
Learn about Android Walks you through the when using LiveData
Architecture different architecture and ViewModels.
Components levels that comprise
an Android app.
 ()  ()  ()

7 Pro-Tips for Understanding ViewModels:


Room migrations with Persistence,
Room onSaveInstanceS
 ()
tate(), Restoring
 ()
UI State and
Some tips on getting
How database
Loaders
the most out of Room.
migration to Room  ()
works under the hood.
This post is the
second in a series
exploring the ins and
outs of ViewModel.

Additional resources

Try Android room with a view (), a codelab that shows how to use Room, ViewModel,
and LiveData.
The Sun ower () demo app demonstrates best practices with architecture
components.
The Github Browser Sample () uses architecture components with Dagger 2.
Our Github repo contains other small samples () demonstrating how to use
architecture components.
Adding Components to your Project
Before getting started, we recommend reading the Architecture Components Guide to App Architecture (). The guide has some useful
principles that apply to all Android apps, and shows how to use the Architecture Components together.

Architecture Components are available from Google's Maven repository. To use them, follow these steps:

Add the Google Maven repository

Android Studio projects aren't con gured to access this repository by default.

To add it to your project, open the build.gradle le for your project (not the ones for your app or module) and add the google()
repository as shown below:

allprojects { 
  repositories {
      google()
      jcenter()
  }
}

Declaring dependencies

Open the build.gradle le for your app or module and add the artifacts that you need as dependencies. You can add all dependencies,
or choose a subset.

AndroidX

Current versions of Arch components are being developed using the AndroidX packages. These are listed rst where available, and differ
in name from the previous (1.X) versions.

For more information about the AndroidX refactor, and how it affects class packages and module IDs, see the AndroidX refactor
documentation ().

Kotlin

Kotlin extension modules are supported for several AndroidX dependencies labeled with // use -ktx for Kotlin below, just replace
e.g.:

implementation "androidx.lifecycle:lifecycle-viewmodel:$lifecycle_version" // use -ktx for Kotlin 

with

implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle_version" 

More information, including docs for Kotlin extensions, can be found in the ktx documentation ().

Note: For Kotlin based apps, make sure you use kapt instead of annotationProcessor. You should also add the kotlin-kapt plugin.

Futures

Dependencies for Futures.

dependencies { 
  def futures_version = "1.0.0-alpha02"
  implementation "androidx.concurrent:concurrent-futures:$futures_version"
}

Lifecycle

Dependencies for Lifecycle (), including LiveData () and ViewModel ().

AndroidX

dependencies { 
  def lifecycle_version = "2.0.0"

  // ViewModel and LiveData


  implementation "androidx.lifecycle:lifecycle-extensions:$lifecycle_version"
  // alternatively - just ViewModel
  implementation "androidx.lifecycle:lifecycle-viewmodel:$lifecycle_version" // use -ktx for Kotlin
  // alternatively - just LiveData
  implementation "androidx.lifecycle:lifecycle-livedata:$lifecycle_version"
  // alternatively - Lifecycles only (no ViewModel or LiveData). Some UI
  //     AndroidX libraries use this lightweight import for Lifecycle
  implementation "androidx.lifecycle:lifecycle-runtime:$lifecycle_version"

  annotationProcessor "androidx.lifecycle:lifecycle-compiler:$lifecycle_version" // use kapt for Kotlin


  // alternately - if using Java8, use the following instead of lifecycle-compiler
  implementation "androidx.lifecycle:lifecycle-common-java8:$lifecycle_version"

  // optional - ReactiveStreams support for LiveData


  implementation "androidx.lifecycle:lifecycle-reactivestreams:$lifecycle_version" // use -ktx for Kotlin

  // optional - Test helpers for LiveData


  testImplementation "androidx.arch.core:core-testing:$lifecycle_version"
}

Pre-AndroidX

dependencies { 
  def lifecycle_version = "1.1.1"

  // ViewModel and LiveData


  implementation "android.arch.lifecycle:extensions:$lifecycle_version"
  // alternatively - just ViewModel
  implementation "android.arch.lifecycle:viewmodel:$lifecycle_version" // use -ktx for Kotlin
  // alternatively - just LiveData
  implementation "android.arch.lifecycle:livedata:$lifecycle_version"
  // alternatively - Lifecycles only (no ViewModel or LiveData).
  //     Support library depends on this lightweight import
  implementation "android.arch.lifecycle:runtime:$lifecycle_version"

  annotationProcessor "android.arch.lifecycle:compiler:$lifecycle_version" // use kapt for Kotlin


  // alternately - if using Java8, use the following instead of compiler
  implementation "android.arch.lifecycle:common-java8:$lifecycle_version"

  // optional - ReactiveStreams support for LiveData


  implementation "android.arch.lifecycle:reactivestreams:$lifecycle_version"

  // optional - Test helpers for LiveData


  testImplementation "android.arch.core:core-testing:$lifecycle_version"
}

Room

Dependencies for Room (), including testing Room migrations () and Room RxJava ()

AndroidX


dependencies { 
  def room_version = "2.1.0-alpha04"

  implementation "androidx.room:room-runtime:$room_version"
  annotationProcessor "androidx.room:room-compiler:$room_version" // use kapt for Kotlin

  // optional - RxJava support for Room


  implementation "androidx.room:room-rxjava2:$room_version"

  // optional - Guava support for Room, including Optional and ListenableFuture


  implementation "androidx.room:room-guava:$room_version"

  // optional - Coroutines support for Room


  implementation "androidx.room:room-coroutines:$room_version"

  // Test helpers
  testImplementation "androidx.room:room-testing:$room_version"
}

Pre-AndroidX

dependencies { 
  def room_version = "1.1.1"

  implementation "android.arch.persistence.room:runtime:$room_version"
  annotationProcessor "android.arch.persistence.room:compiler:$room_version" // use kapt for Kotlin

  // optional - RxJava support for Room


  implementation "android.arch.persistence.room:rxjava2:$room_version"

  // optional - Guava support for Room, including Optional and ListenableFuture


  implementation "android.arch.persistence.room:guava:$room_version"

  // Test helpers
  testImplementation "android.arch.persistence.room:testing:$room_version"
}

Paging

Dependencies for Paging ()

AndroidX

dependencies { 
  def paging_version = "2.1.0"

  implementation "androidx.paging:paging-runtime:$paging_version" // use -ktx for Kotlin

  // alternatively - without Android dependencies for testing


  testImplementation "androidx.paging:paging-common:$paging_version" // use -ktx for Kotlin

  // optional - RxJava support


  implementation "androidx.paging:paging-rxjava2:$paging_version" // use -ktx for Kotlin
}

Pre-AndroidX

dependencies { 
  def paging_version = "1.0.0"

  implementation "android.arch.paging:runtime:$paging_version"

  // alternatively - without Android dependencies for testing


  testImplementation "android.arch.paging:common:$paging_version"

  // optional - RxJava support


  implementation "android.arch.paging:rxjava2:$paging_version"
}

Navigation

Dependencies for Navigation ().

Navigation classes are already in the androidx.navigation package, but currently depend on Support Library 28.0.0, and associated Arch
component versions. Version of Navigation with AndroidX dependencies will be released in the future.

dependencies { 
  def nav_version = "1.0.0-alpha11"

  implementation "android.arch.navigation:navigation-fragment:$nav_version" // use -ktx for Kotlin


  implementation "android.arch.navigation:navigation-ui:$nav_version" // use -ktx for Kotlin
}

Safe args

For Safe args (), add the following classpath in your top level build.gradle le

buildscript { 
  repositories {
      google()
  }
  dependencies {
      classpath "android.arch.navigation:navigation-safe-args-gradle-plugin:1.0.0-alpha11"
  }
}

And in your app or module build.gradle le

apply plugin: "androidx.navigation.safeargs" 


// alternatively - for Kotlin-only modules
apply plugin: "androidx.navigation.safeargs.kotlin"

WorkManager

Dependencies for WorkManager ().

WorkManager classes are already in the androidx.work package, but currently depend on Support Library 27.1, and associated Arch
component versions. Version of WorkManager with AndroidX dependencies will be released in the future.

WorkManager requires compileSdk version 28 or higher.

dependencies { 
  def work_version = "1.0.0-beta03"

  implementation "android.arch.work:work-runtime:$work_version" // use -ktx for Kotlin+Coroutines

  // optional - RxJava2 support


  implementation "android.arch.work:work-rxjava2:$work_version"

  // optional - Test helpers


  androidTestImplementation "android.arch.work:work-testing:$work_version"
}

For more information, see Add Build Dependencies ().


Biblioteca de vinculación de datos
En este documento se explica la manera de usar la biblioteca de vinculación de datos para escribir diseños declarativos y minimizar el
código de adhesión necesario para vincular la lógica y los diseños de tu aplicación.

La biblioteca de vinculación de datos ofrece exibilidad y amplia compatibilidad. Es una biblioteca de compatibilidad, de modo que
puedes usarla con todas las versiones de la plataforma Android hasta Android 2.1 (a partir del nivel de API 7).

Para usar la vinculación de datos, se necesita el complemento de Android para Gradle 1.5.0-alpha1 o una versión posterior.

Entorno de compilación

Para comenzar con la vinculación de datos, descarga la biblioteca desde el repositorio de compatibilidad de Android SDK Manager.

Para con gurar el uso de vinculación de datos en tu app, agrega el elemento dataBinding a tu archivo build.gradle en el módulo de
esta.

Usa el siguiente fragmento de código para con gurar la vinculación de datos:

android { 
  ....
  dataBinding {
      enabled = true
  }
}

Si hay un módulo de app que depende de una biblioteca que usa vinculación de datos, también debe con gurarse la vinculación de datos
en el archivo build.gradle de este módulo.

A su vez, asegúrate de usar una versión compatible de Android Studio. Android Studio 1.3 y las versiones posteriores proporcionan
compatibilidad con la vinculación de datos como se describe en Compatibilidad de Android Studio con la vinculación de datos ().

Archivos de diseño de vinculación de datos

Cómo escribir tu primer conjunto de expresiones de vinculación de datos

Los archivos de diseño de vinculación de datos son un poco diferentes y comienzan con una etiqueta raíz layout seguida de un elemento
data y un elemento raíz view. Este elemento view representa lo que sería tu raíz en un archivo de diseño sin vinculación. Un archivo de
ejemplo tiene el siguiente aspecto:

<?xml version="1.0" encoding="utf-8"?> 


<layout xmlns:android="http://schemas.android.com/apk/res/android">
 <data>
     <variable name="user" type="com.example.User"/>
 </data>
 <LinearLayout
     android:orientation="vertical"
     android:layout_width="match_parent"
     android:layout_height="match_parent">
     <TextView android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:text="@{user.firstName}"/>
     <TextView android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:text="@{user.lastName}"/>
 </LinearLayout>
</layout>

La variable de usuario dentro de datos describe una propiedad que se puede usar dentro de este diseño.

<variable name="user" type="com.example.User"/> 


Las expresiones dentro del diseño se escriben en las propiedades del atributo usando la sintaxis “@{}”. Aquí, el texto de TextView se ja
en la propiedad del usuario rstName:

<TextView android:layout_width="wrap_content" 
        android:layout_height="wrap_content"
        android:text="@{user.firstName}"/>

Objeto de datos

Supongamos por ahora que tienes un objeto Java (POJO) antiguo para el usuario:

public class User { 


 public final String firstName;
 public final String lastName;
 public User(String firstName, String lastName) {
     this.firstName = firstName;
     this.lastName = lastName;
 }
}

Este tipo de objeto tiene datos que nunca cambian. Es común que las aplicaciones tengan datos que se lean una vez y nunca se vuelvan
a cambiar. También es posible usar objetos JavaBeans:

public class User { 


 private final String firstName;
 private final String lastName;
 public User(String firstName, String lastName) {
     this.firstName = firstName;
     this.lastName = lastName;
 }
 public String getFirstName() {
     return this.firstName;
 }
 public String getLastName() {
     return this.lastName;
 }
}

Desde la perspectiva de la vinculación de datos, estas dos clases son equivalentes. La expresión @{user.firstName} usada para el
atributo de TextView android:text accederá al campo firstName en la primera clase y el método getFirstName() en la segunda. De
manera alternativa, también se resolverá a firstName() si ese método existe.

Vinculación de datos

De forma predeterminada, se generará una clase Binding según el nombre del archivo de diseño; se aplicará una conversión a caso
Pascal y se agregará el su jo “Binding”. El archivo de diseño anterior llevaba el nombre main_activity.xml. Por lo tanto, la clase
generada se denominó MainActivityBinding. Esta clase contiene todas las vinculaciones de las propiedades de diseño (p. ej., la
variable user) con los elementos View del diseño y determina la manera de asignar valores para las expresiones de vinculación. La
manera más sencilla de crear las vinculaciones es proceder durante la expansión:

@Override 
protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 MainActivityBinding binding = DataBindingUtil.setContentView(this, R.layout.main_activity);
 User user = new User("Test", "User");
 binding.setUser(user);
}

¡Eso es todo! Ejecuta la aplicación. Verás “Test User” en la IU. De manera alternativa, puedes obtener la vista con lo siguiente:

MainActivityBinding binding = MainActivityBinding.inflate(getLayoutInflater()); 

Si usas los elementos de vinculación de datos dentro de un adaptador ListView o RecyclerView, tal vez pre eras usar lo siguiente:

ListItemBinding binding = ListItemBinding.inflate(layoutInflater, viewGroup, false); 


//or
ListItemBinding binding = DataBindingUtil.inflate(layoutInflater, R.layout.list_item, viewGroup, false);

Manejo de eventos

La vinculación de datos te permite escribir expresiones que manejan eventos enviados desde las vistas (p. ej., onClick). Los nombres de
atributos de eventos se rigen por el nombre del método de receptor, con algunas excepciones. Por ejemplo, View.OnLongClickListener
() tiene un método onLongClick() (). Por lo tanto, el atributo para este evento es android:onLongClick. Hay dos maneras de manejar
un evento.

Referencias de métodos (): en tus expresiones, puedes hacer referencia a métodos que se adecuan a la rma del método de
receptor. Cuando una expresión se evalúa como una referencia de método, la vinculación de datos ajusta la referencia de método y
el objeto de propietario de un receptor, y con gura ese receptor en la vista de destino. Si la expresión se evalúa como nula, la
vinculación de datos no genera un receptor y, como alternativa, con gura un receptor nulo.

Vinculaciones de receptores (): son expresiones lambda que se evalúan cuando sucede el evento. La vinculación de datos siempre
crea un receptor y lo con gura en la vista. Cuando se envía el evento, el receptor evalúa la expresión lambda.

Referencias de métodos

Los eventos se pueden vincular directamente con métodos de control, procedimiento similar a la alternativa por la cual se puede asignar
android:onClick a un método en una actividad. Una de las mayores ventajas en comparación con el atributo View#onClick es que la
expresión se procesa en el momento de la compilación, de modo que si el método no existe o su rma no es correcta, observarás un
error en el momento de compilación.

La mayor diferencia entre referencias de métodos y vinculaciones de receptor es que la implementación del receptor real se crea cuando
los datos se vinculan, no cuando el evento se activa. Si pre eres evaluar la expresión cuando tiene lugar el evento, debes usar la
vinculación de receptores ().

Para asignar un evento a su controlador, usa una expresión de vinculación normal, con el valor que representa el nombre de método que
se llamará. Por ejemplo, si tu objeto de datos tiene dos métodos:

public class MyHandlers { 


  public void onClickFriend(View view) { ... }
}

La expresión de vinculación puede asignar el receptor de clics para un elemento View:

<?xml version="1.0" encoding="utf-8"?> 


<layout xmlns:android="http://schemas.android.com/apk/res/android">
 <data>
     <variable name="handlers" type="com.example.Handlers"/>
     <variable name="user" type="com.example.User"/>
 </data>
 <LinearLayout
     android:orientation="vertical"
     android:layout_width="match_parent"
     android:layout_height="match_parent">
     <TextView android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:text="@{user.firstName}"
         android:onClick="@{handlers::onClickFriend}"/>
 </LinearLayout>
</layout>

Ten en cuenta que la rma del método de la expresión debe coincidir exactamente con la rma del método del objeto receptor.

Vinculaciones de receptores

Las vinculaciones de receptores son expresiones de vinculación que se ejecutan cuando tiene lugar un evento. Son similares a las
referencias de métodos, pero te permiten ejecutar expresiones de vinculación de datos arbitrarios. Esta función se encuentra disponible
a partir de la versión 2.0 del complemento de Android para Gradle.

En las referencias de métodos, los parámetros del método deben coincidir con los parámetros del receptor de eventos. En vinculaciones
de receptores, solo tu valor de retorno debe coincidir con el valor de retorno del receptor que se espera (a menos que se espere uno
vacío). Por ejemplo, puedes tener una clase presentadora que tenga el siguiente método:
public class Presenter { 
  public void onSaveClick(Task task){}
}

Luego puedes vincular el evento de clic con tu clase de la siguiente manera:

<?xml version="1.0" encoding="utf-8"?> 


<layout xmlns:android="http://schemas.android.com/apk/res/android">
    <data>
        <variable name="task" type="com.android.example.Task" />
        <variable name="presenter" type="com.android.example.Presenter" />
    </data>
    <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent">
        <Button android:layout_width="wrap_content" android:layout_height="wrap_content"
        android:onClick="@{() -> presenter.onSaveClick(task)}" />
    </LinearLayout>
</layout>

Los receptores están representados por expresiones Lambda que solo están permitidas como elementos de raíz de tus expresiones.
Cuando se usa un callback en una expresión, la vinculación de datos genera de manera automática el receptor necesario y se registra
para el evento. Cuando la vista activa el evento, la vinculación de datos evalúa la expresión dada. Al igual que en las expresiones de
vinculación regulares, se obtiene de todas formas la seguridad de tipo “null” y de subprocesos de vinculación de datos mientras se
evalúan estas expresiones de receptor.

Ten en cuenta que en el ejemplo anterior no de nimos el parámetro view que se pasa a onClick(android.view.View) (). Las
vinculaciones de receptores proporcionan dos opciones para los parámetros de receptor: puedes ignorar todos los parámetros del
método u otorgarles un nombre a todos ellos. Si pre eres nombrar los parámetros, puedes usarlos en tu expresión. Por ejemplo, la
expresión anterior podría escribirse de esta manera:

android:onClick="@{(view) -> presenter.onSaveClick(task)}" 

Como alternativa, si deseas usar el parámetro en la expresión, podría funcionar de la siguiente manera:

public class Presenter { 


  public void onSaveClick(View view, Task task){}
}

android:onClick="@{(theView) -> presenter.onSaveClick(theView, task)}" 

Puedes usar una expresión lambda con más de un parámetro:

public class Presenter { 


  public void onCompletedChanged(Task task, boolean completed){}
}

<CheckBox android:layout_width="wrap_content" android:layout_height="wrap_content" 


      android:onCheckedChanged="@{(cb, isChecked) -> presenter.completeChanged(task, isChecked)}" />

Si el evento que recibes muestra un valor cuyo tipo no es void, tus expresiones también deben mostrar el mismo tipo de valor. Por
ejemplo, si deseas recibir el evento de clic largo, tu expresión debe mostrar boolean.

public class Presenter { 


  public boolean onLongClick(View view, Task task){}
}

android:onLongClick="@{(theView) -> presenter.onLongClick(theView, task)}" 

Si la expresión no se puede evaluar debido a objetos null, la vinculación de datos muestra el valor de Java predeterminado para ese tipo.
Por ejemplo, null para tipos de referencia, 0 para int, false para boolean, etc.

Si debes usar una expresión con un predicado (p. ej., ternario), puedes usar void como un símbolo.

android:onClick="@{(v) -> v.isVisible() ? doSomething() : void}" 


Evitar receptores complejos

Las expresiones de receptor son muy poderosas y pueden facilitar mucho la lectura de tu código. Por otra parte, los receptores que
tienen expresiones complejas di cultan la lectura de tus diseños e imposibilitan su mantenimiento. Estas expresiones deben ser tan
sencillas como el paso de datos disponibles de tu IU a tu método callback. Debes implementar cualquier lógica de negocios dentro del
método callback que invocaste desde la expresión de receptor.

Existen algunos controladores de eventos de clic especializados y necesitan un atributo que no sea android:onClick para evitar un
con icto. Se han creado los siguientes atributos para evitar con ictos:

Clase Establecedor de receptores Atributo

SearchView () setOnSearchClickListener(View.OnClickListener) () android:onSearchClick

ZoomControls () setOnZoomInClickListener(View.OnClickListener) () android:onZoomIn

ZoomControls () setOnZoomOutClickListener(View.OnClickListener) () android:onZoomOut

Detalles de diseño

Importaciones

Dentro del elemento data es posible usar varios elementos import o que no se use ninguno. Estos permiten hacer una referencia
sencilla a clases dentro de tu archivo de diseño, al igual que en Java.

<data> 
  <import type="android.view.View"/>
</data>

Ahora, se puede usar el elemento View dentro de tu expresión de vinculación:

<TextView 
 android:text="@{user.lastName}"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"
 android:visibility="@{user.isAdult ? View.VISIBLE : View.GONE}"/>

Cuando existen con ictos en los nombres de clases, se puede modi car el de una de estas puede con un “alias”:

<import type="android.view.View"/> 
<import type="com.example.real.estate.View"
      alias="Vista"/>

Vista se puede usar para hacer referencia a com.example.real.estate.View y View se puede usar para hacer referencia a
android.view.View dentro del archivo de diseño. Los tipos importados pueden usarse como referencias de tipos en variables y
expresiones:

<data> 
  <import type="com.example.User"/>
  <import type="java.util.List"/>
  <variable name="user" type="User"/>
  <variable name="userList" type="List&lt;User&gt;"/>
</data>

Nota: En Android Studio aún no se manejan importaciones. Por lo tanto, es posible que la función de autocompletar para variables importadas no funcione
en tu IDE. De todos modos, tu aplicación podrá compilarse bien y podrás corregir el error de IDE usando nombres totalmente cali cados en tus de niciones
de variables.

<TextView 
 android:text="@{((User)(user.connection)).lastName}"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"/>

Los tipos importados también se pueden usar al hacer referencia a campos y métodos estáticos en las expresiones:
<data> 
  <import type="com.example.MyStringUtils"/>
  <variable name="user" type="com.example.User"/>
</data>

<TextView
 android:text="@{MyStringUtils.capitalize(user.lastName)}"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"/>

Como en Java, java.lang.* se importa de manera automática.

Variables

Cualquier número de elementos variable se puede usar dentro del elemento data. En cada elemento variable se describe una
propiedad que puede establecerse en el diseño que se usará en expresiones de vinculación, dentro del archivo de diseño.

<data> 
  <import type="android.graphics.drawable.Drawable"/>
  <variable name="user"  type="com.example.User"/>
  <variable name="image" type="Drawable"/>
  <variable name="note"  type="String"/>
</data>

Los tipos de variables se inspeccionan en el momento de compilación, de modo que si una variable implementa
android.databinding.Observable o es una colección observable (), esto debe re ejarse en el tipo. Si la variable es una clase base o
interfaz que no implementa la interfaz Observable*, las variables no se observarán.

Cuando hay diferentes archivos de diseño para varias con guraciones (p. ej., horizontal o vertical), se combinarán las variables. No debe
haber de niciones variables con ictivas entre estos archivos de diseño.

La clase Binding generada tendrá un establecedor y un captador para cada una de las variables descritas. Las variables tomarán los
valores Java predeterminados hasta que el establecedor se llame — null para tipos de referencia, 0 para int, false para boolean, etc.

Una variable especial llamada context se genera para usarse en expresiones de vinculación según sea necesario. El valor para context
es Context del elemento getContext() () del elemento raíz View. La variable context se reemplazará por una declaración de la variable
explícita que lleve ese nombre.

Nombres de clases de vinculación personalizada

De forma predeterminada, una clase Binding se genera según el nombre del archivo de diseño; se aplican mayúsculas al principio, se
eliminan los guiones bajos ( _ ), se aplican mayúsculas a las letras que siguen a estos y se agrega el su jo “Binding”. Esta clase se
ubicará en un paquete de vinculación de datos bajo el paquete del módulo. Por ejemplo, a partir del archivo de diseño contact_item.xml
se generará ContactItemBinding. Si el paquete del módulo es com.example.my.app, este luego se dispondrá en
com.example.my.app.databinding.

Las clases Binding se pueden volver a nombrar o se pueden disponer en paquetes diferentes ajustando el atributo class del elemento
data. Por ejemplo:

<data class="ContactItem"> 
  ...
</data>

Esto genera la clase Binding como ContactItem en el paquete de vinculación de datos del paquete del módulo. Si la clase debe
generarse en un paquete diferente dentro del paquete del módulo, puede contener un pre jo “.”:

<data class=".ContactItem"> 
  ...
</data>

En este caso, ContactItem se genera en el paquete del módulo directamente. Se puede usar cualquier paquete si se proporciona el
paquete completo:

<data class="com.example.ContactItem"> 
  ...
</data>

Parámetros include

Se pueden pasar variables a la vinculación de un diseño incluido desde el diseño contenedor usando el espacio de nombres de la
aplicación y el nombre de la variable de un atributo:

<?xml version="1.0" encoding="utf-8"?> 


<layout xmlns:android="http://schemas.android.com/apk/res/android"
      xmlns:bind="http://schemas.android.com/apk/res-auto">
 <data>
     <variable name="user" type="com.example.User"/>
 </data>
 <LinearLayout
     android:orientation="vertical"
     android:layout_width="match_parent"
     android:layout_height="match_parent">
     <include layout="@layout/name"
         bind:user="@{user}"/>
     <include layout="@layout/contact"
         bind:user="@{user}"/>
 </LinearLayout>
</layout>

Aquí, debe haber una variable user en los archivos de diseño name.xml y contact.xml.

La vinculación de datos no admite el parámetro include como un campo secundario directo de un elemento merge. Por ejemplo, el
siguiente diseño no es compatible:

<?xml version="1.0" encoding="utf-8"?> 


<layout xmlns:android="http://schemas.android.com/apk/res/android"
      xmlns:bind="http://schemas.android.com/apk/res-auto">
 <data>
     <variable name="user" type="com.example.User"/>
 </data>
 <merge>
     <include layout="@layout/name"
         bind:user="@{user}"/>
     <include layout="@layout/contact"
         bind:user="@{user}"/>
 </merge>
</layout>

Lenguaje de expresión

Funciones comunes

El lenguaje de expresión es muy similar a una expresión Java. Estos son los mismos:

Matemática + - / * %

Concatenación de strings +
Lógica && ||
Ejecutable & | ^
Unario + - ! ~
Cambio >> >>> <<
Comparación == > < >= <=
instanceof

Agrupación ()
Literales: caracteres, strings, números, null

Transmisión
Llamadas de métodos
Acceso al campo
Acceso a la matriz []
Operador ternario ?:

Ejemplos:

android:text="@{String.valueOf(index + 1)}" 
android:visibility="@{age < 13 ? View.GONE : View.VISIBLE}"
android:transitionName='@{"image_" + id}'

Operaciones faltantes

Faltan algunas operaciones de la sintaxis de expresión que puedes usar en Java.

this

super

new

Invocación genérica explícita

Operador de incorporación nulo

El operador de incorporación nulo (??) elige el operando izquierdo si no es nulo o el derecho si es nulo.

android:text="@{user.displayName ?? user.lastName}" 

Esto es funcionalmente equivalente a:

android:text="@{user.displayName != null ? user.displayName : user.lastName}" 

Referencia de propiedades

La primera ya se analizó en Cómo escribir tus primeras expresiones de vinculación de datos (): referencias de JavaBean de forma corta.
Cuando una expresión hace referencia a una propiedad de una clase, usa el mismo formato para campos, captadores y objetos
ObservableField.

android:text="@{user.lastName}" 

Evitar NullPointerException

El código de vinculación de datos generado veri ca de manera automática los elementos null y evita las excepciones de puntero nulo.
Por ejemplo, en la expresión @{user.name}, si user es null, a user.name se le asignará su valor predeterminado (null). Al hacer referencia
a user.age, donde “age” es un int, se jaba de forma predeterminada en 0.

Colecciones

Colecciones comunes: por cuestiones de conveniencia, se puede acceder a matrices, listas, listas no precisas y mapas usando el
operador [].

<data> 
  <import type="android.util.SparseArray"/>
  <import type="java.util.Map"/>
  <import type="java.util.List"/>
  <variable name="list" type="List&lt;String&gt;"/>
  <variable name="sparse" type="SparseArray&lt;String&gt;"/>
  <variable name="map" type="Map&lt;String, String&gt;"/>
  <variable name="index" type="int"/>
  <variable name="key" type="String"/>
</data>

android:text="@{list[index]}"

android:text="@{sparse[index]}"

android:text="@{map[key]}"

Literales de strings

Cuando se usan comillas simples en el valor de atributo, usar comillas dobles en la expresión es sencillo:

android:text='@{map["firstName"]}' 

También es posible usar comillas dobles para encerrar el valor de atributo. Cuando se hace eso, en los literales de strings deben usarse '
o la comilla inversa (`).

android:text="@{map[`firstName`}" 
android:text="@{map['firstName']}"

Recursos

Es posible ingresar recursos como parte de las expresiones que usan la sintaxis normal:

android:padding="@{large? @dimen/largePadding : @dimen/smallPadding}" 

Las strings de formato y los plurales se pueden evaluar proporcionando parámetros:

android:text="@{@string/nameFormat(firstName, lastName)}" 
android:text="@{@plurals/banana(bananaCount)}"

Cuando un plural toma varios parámetros, todos ellos se deben pasar:


Have an orange
Have %d oranges

android:text="@{@plurals/orange(orangeCount, orangeCount)}"

Algunos recursos requieren una evaluación de tipos explícita.

Tipo Referencia normal Referencia de expresión

String[] @array @stringArray

int[] @array @intArray

TypedArray @array @typedArray

Animator @animator @animator

StateListAnimator @animator @stateListAnimator

color int @color @color

ColorStateList @color @colorStateList

Objetos de datos

Cualquier objeto Java antiguos sin formato (POJO) se puede usar para la vinculación de datos, pero la modi cación de un POJO no hará
que la IU se actualice. El poder real de la vinculación de datos se puede usar al proporcionar a tus objetos de datos la capacidad de emitir
noti caciones cuando cambian los datos. Existen tres mecanismos diferentes de noti cación de cambios de datos: los Objetos
observables (), los campos observables () y las colecciones observables ().

Cuando uno de estos objetos de datos observables dependa de la IU y una propiedad de objetos de datos cambie, la IU se actualizará de
forma automática.

Objetos observables
Una clase que implemente la interfaz android.databinding.Observable permitirá que la vinculación adjunte un único receptor a un
objeto vinculado para recibir los cambios de todas las propiedades en ese objeto.

La interfaz android.databinding.Observable tiene un mecanismo para agregar y eliminar receptores, pero la noti cación depende del
desarrollador. A n de facilitar el desarrollo, se creó la clase base android.databinding.BaseObservable para implementar el
mecanismo de registro de receptores. El implementador de clases de datos es aún responsable de enviar noti caciones cuando cambian
las propiedades. Esto se realiza asignando una anotación android.databinding.Bindable al captador y realizando una noti cación en
el receptor.

private static class User extends BaseObservable { 


 private String firstName;
 private String lastName;
 @Bindable
 public String getFirstName() {
     return this.firstName;
 }
 @Bindable
 public String getLastName() {
     return this.lastName;
 }
 public void setFirstName(String firstName) {
     this.firstName = firstName;
     notifyPropertyChanged(BR.firstName);
 }
 public void setLastName(String lastName) {
     this.lastName = lastName;
     notifyPropertyChanged(BR.lastName);
 }
}

La anotación android.databinding.Bindable genera una entrada en el archivo de la clase BR durante la compilación. El archivo de
clase BR se generará en el paquete del módulo. Si la clase base para clases de datos no se puede cambiar, se puede implementar la
interfaz android.databinding.Observable usando el android.databinding.PropertyChangeRegistry apropiado para almacenar y
noti car receptores de modo e ciente.

Objetos ObservableField

Crear clases android.databinding.Observable implica un poco de trabajo; por ello, los desarrolladores que deseen ahorrar tiempo o
tengan pocas propiedades podrán usar android.databinding.ObservableField y sus elementos del mismo nivel:
android.databinding.ObservableBoolean, android.databinding.ObservableByte, android.databinding.ObservableChar,
android.databinding.ObservableShort, android.databinding.ObservableInt, android.databinding.ObservableLong,
android.databinding.ObservableFloat, android.databinding.ObservableDouble y
android.databinding.ObservableParcelable. Los ObservableFields son objetos observables independientes que tienen un único
campo. Las versiones primitivas evitan la conversión boxing y unboxing durante operaciones de acceso. Para usarlas, crea un campo
nal público en la clase de datos:

private static class User { 


 public final ObservableField<String> firstName =
     new ObservableField<>();
 public final ObservableField<String> lastName =
     new ObservableField<>();
 public final ObservableInt age = new ObservableInt();
}

¡Eso es todo! Para ingresar el valor, usa los métodos de descriptor de acceso set y get:

user.firstName.set("Google"); 
int age = user.age.get();

Colecciones observables

Algunas aplicaciones usan estructuras más dinámicas para contener datos. Las colecciones observables permiten el acceso con clave a
estos objetos de datos. android.databinding.ObservableArrayMap es útil cuando la clave es un tipo de referencia, como String.
ObservableArrayMap<String, Object> user = new ObservableArrayMap<>(); 
user.put("firstName", "Google");
user.put("lastName", "Inc.");
user.put("age", 17);

En el diseño, se puede acceder al mapa a través de las claves String:

<data> 
  <import type="android.databinding.ObservableMap"/>
  <variable name="user" type="ObservableMap&lt;String, Object&gt;"/>
</data>

<TextView
 android:text='@{user["lastName"]}'
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"/>
<TextView
 android:text='@{String.valueOf(1 + (Integer)user["age"])}'
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"/>

android.databinding.ObservableArrayList es útil cuando la clave es un número entero:

ObservableArrayList<Object> user = new ObservableArrayList<>(); 


user.add("Google");
user.add("Inc.");
user.add(17);

En el diseño, se puede acceder a la lista a través de los índices:

<data> 
  <import type="android.databinding.ObservableList"/>
  <import type="com.example.my.app.Fields"/>
  <variable name="user" type="ObservableList&lt;Object&gt;"/>
</data>

<TextView
 android:text='@{user[Fields.LAST_NAME]}'
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"/>
<TextView
 android:text='@{String.valueOf(1 + (Integer)user[Fields.AGE])}'
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"/>

Vinculación generada

La clase Binding generada vincula las variables de diseño con los elementos View dentro del diseño. Según lo discutido anteriormente, el
nombre y el paquete de la vinculación pueden ser personalizados (). Todas las clases de vinculación generadas extienden
android.databinding.ViewDataBinding.

Creación

La vinculación debe crearse poco después del aumento para garantizar que la jerarquía de elementos View no se vea interrumpida antes
de la vinculación con las vistas mediante expresiones dentro del diseño. Hay algunos modos de realizar vinculaciones con un diseño. El
más común consiste en usar los métodos estáticos en la clase Binding. El método in ate aumenta la jerarquía de elementos View y se
vincula a ella en un paso. Hay una versión más simple que solo toma una clase LayoutInflater () y uno que toma una clase ViewGroup
() también:

MyLayoutBinding binding = MyLayoutBinding.inflate(layoutInflater); 


MyLayoutBinding binding = MyLayoutBinding.inflate(layoutInflater, viewGroup, false);

Si se aumentó el diseño con un mecanismo diferente, es posible vincularlo por separado:

MyLayoutBinding binding = MyLayoutBinding.bind(viewRoot); 


A veces, la vinculación no se puede conocer por adelantado. En esos casos, se puede crear la vinculación usando la clase
android.databinding.DataBindingUtil:

ViewDataBinding binding = DataBindingUtil.inflate(LayoutInflater, layoutId, 


  parent, attachToParent);
ViewDataBinding binding = DataBindingUtil.bindTo(viewRoot, layoutId);

Vistas con ID

Se generará un campo nal público para cada elemento View con un ID en el diseño. La compilación realiza un único paso en la jerarquía
View, con lo cual se extraen los elementos View con los ID. Este mecanismo puede ser más rápido que llamar a ndViewById para varios
elementos View. Por ejemplo:

<layout xmlns:android="http://schemas.android.com/apk/res/android"> 
 <data>
     <variable name="user" type="com.example.User"/>
 </data>
 <LinearLayout
     android:orientation="vertical"
     android:layout_width="match_parent"
     android:layout_height="match_parent">
     <TextView android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:text="@{user.firstName}"
 android:id="@+id/firstName"/>
     <TextView android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:text="@{user.lastName}"
android:id="@+id/lastName"/>
 </LinearLayout>
</layout>

Generará una clase Binding con:

public final TextView firstName; 


public final TextView lastName;

Los ID no son en absoluto tan necesarios como ante la ausencia de vinculación de datos, pero hay de todos modos algunas instancias
en las cuales es necesario acceder a los elementos View desde el código.

Variables

A cada variable se le otorgarán métodos de descriptores de acceso.

<data> 
  <import type="android.graphics.drawable.Drawable"/>
  <variable name="user"  type="com.example.User"/>
  <variable name="image" type="Drawable"/>
  <variable name="note"  type="String"/>
</data>

Se generarán establecedores y captadores en la vinculación:

public abstract com.example.User getUser(); 


public abstract void setUser(com.example.User user);
public abstract Drawable getImage();
public abstract void setImage(Drawable image);
public abstract String getNote();
public abstract void setNote(String note);

ViewStubs

Los ViewStub () se diferencian un tanto de los elementos Views normales. Comienzan sin ser visibles y cuando se vuelven visibles, o
reciben indicaciones explícitas para aumentar, se reemplazan en el diseño aumentando otro diseño.
Debido a que ViewStub en esencia desaparece de la jerarquía de elementos View, el elemento View del objeto de vinculación también
debe desaparecer para permitir la colección. Debido a que los elementos View son de nitivos, un objeto
android.databinding.ViewStubProxy toma el lugar de ViewStub, lo cual otorga al desarrollador acceso a ViewStub cuando existe y
también acceso a la jerarquía aumentada de elementos View cuando se aumenta ViewStub.

Cuando se aumenta otro diseño, se debe establecer una vinculación para el diseño nuevo. Por lo tanto, ViewStubProxy debe recibir el
elemento ViewStub.OnInflateListener () de ViewStub y establecer la vinculación en ese momento. Ya que solo uno puede existir,
ViewStubProxy permite al desarrollador establecer en este un elemento OnInflateListener que llamará después de establecer la
vinculación.

Vinculación avanzada

Variables dinámicas

A veces, la clase Binding especí ca no será conocida. Por ejemplo, un elemento RecyclerView.Adapter () que funciona con diseños
arbitrarios no reconocerá la clase Binding especí ca. Debe, de todos modos, asignar el valor Binding durante onBindViewHolder(VH,
int) ().

En este ejemplo, todos los diseños que RecyclerView vincula tienen una variable “item”. BindingHolder tiene un método getBinding
que muestra la base android.databinding.ViewDataBinding.

public void onBindViewHolder(BindingHolder holder, int position) { 


 final T item = mItems.get(position);
 holder.getBinding().setVariable(BR.item, item);
 holder.getBinding().executePendingBindings();
}

Vinculación inmediata

Cuando una variable o un objeto observable cambien, la vinculación se programará para cambiar antes del siguiente fotograma. Sin
embargo, hay momentos en los cuales la vinculación debe ejecutarse de inmediato. Para forzar la ejecución, usa el método
ViewDataBinding.executePendingBindings().

Subproceso en segundo plano

Puedes cambiar tu modelo de datos en un subproceso en segundo plano mientras no sea una colección. La vinculación de datos
localizará cada variable o campo durante la evaluación para evitar cualquier problema de concurrencia.

Establecedores de atributos

Cada vez que un valor vinculado cambia, la clase Binding generada debe llamar a un método establecedor en el elemento View con la
expresión de vinculación. El framework de vinculación de datos tiene maneras de personalizar el método que se llamará para establecer
el valor.

Establecedores automáticos

Para un atributo, la vinculación de datos intenta encontrar el método setAttribute. El espacio de nombres para el atributo no tiene
importancia; solo la tiene el nombre del atributo.

Por ejemplo, una expresión asociada con el atributo android:text de TextView buscará un elemento setText(String). Si la expresión
muestra un int, la vinculación de datos buscará un método setText(int). Procura que la expresión muestre el tipo correcto. Si es
necesario, realiza una transmisión. Ten en cuenta que la vinculación de datos funcionará incluso si no existe un atributo con el nombre
en cuestión. Luego, podrás “crear” de manera sencilla atributos para cualquier establecedor usando la vinculación de datos. Por ejemplo,
el elemento DrawerLayout de respaldo no tiene atributos, pero tiene muchos establecedores. Puedes usar los establecedores
automáticos para emplear uno de estos.

<android.support.v4.widget.DrawerLayout 
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
  app:scrimColor="@{@color/scrim}"
  app:drawerListener="@{fragment.drawerListener}"/>
Establecedores con nombres restablecidos

Algunos atributos tienen establecedores que no coinciden por nombre. Para estos métodos, se puede asociar un atributo con el
establecedor a través de la anotación android.databinding.BindingMethods. Esto se debe asociar con una clase y contiene
anotaciones de android.databinding.BindingMethod, una por cada método con nombre restablecido. Por ejemplo, el atributo
android:tint se asocia en realidad con setImageTintList(ColorStateList) (), no con setTint.

@BindingMethods({ 
     @BindingMethod(type = "android.widget.ImageView",
                    attribute = "android:tint",
                    method = "setImageTintList"),
})

Es poco probable que los desarrolladores necesiten volver a nombrar establecedores; los atributos del framework de Android ya se han
implementado.

Establecedores personalizados

Algunos atributos necesitan lógica de vinculación personalizada. Por ejemplo, no hay un establecedores asociados para el atributo
android:paddingLeft. Como alternativa, existe setPadding(left, top, right, bottom). Un método de adaptador de vinculación
estático con la anotación android.databinding.BindingAdapter permite al desarrollador personalizar la manera en que se llama a un
establecedor para un atributo.

Ya se han creado BindingAdapter para los atributos de Android. Por ejemplo, a continuación se muestra uno para paddingLeft:

@BindingAdapter("android:paddingLeft") 
public static void setPaddingLeft(View view, int padding) {
 view.setPadding(padding,
                 view.getPaddingTop(),
                 view.getPaddingRight(),
                 view.getPaddingBottom());
}

Los adaptadores de vinculación son útiles para otros tipos de personalización. Por ejemplo, un cargador personalizado se puede llamar
fuera del subproceso para cargar una imagen.

Los adaptadores de vinculación creados por el desarrollador anularán los adaptadores de vinculación de datos predeterminados cuando
haya un con icto.

También puedes tener adaptadores que reciban varios parámetros.

@BindingAdapter({"bind:imageUrl", "bind:error"}) 
public static void loadImage(ImageView view, String url, Drawable error) {
 Picasso.with(view.getContext()).load(url).error(error).into(view);
}

<ImageView app:imageUrl="@{venue.imageUrl}" 
app:error="@{@drawable/venueError}"/>

Se llamará a este adaptador si imageUrl y error se usan para un elemento ImageView, imageUrl es una string y error es un elemento de
diseño.

Los espacios de nombres personalizados se ignoran durante el establecimiento de coincidencias.


También puedes escribir adaptadores para el espacio de nombres de Android.

La vinculación de métodos de adaptadores puede opcionalmente tomar los valores viejos para sus controladores. Un método que toma
valores anteriores y nuevos debe tener todos los valores anteriores para que los atributos aparezcan primeros seguidos de los valores
nuevos:

@BindingAdapter("android:paddingLeft") 
public static void setPaddingLeft(View view, int oldPadding, int newPadding) {
 if (oldPadding != newPadding) {
     view.setPadding(newPadding,
                     view.getPaddingTop(),
                     view.getPaddingRight(),
                     view.getPaddingBottom());
())
 }
}

Los controladores de eventos solo pueden usarse con interfaces o con clases abstractas con un método abstracto. Por ejemplo:

@BindingAdapter("android:onLayoutChange") 
public static void setOnLayoutChangeListener(View view, View.OnLayoutChangeListener oldValue,
     View.OnLayoutChangeListener newValue) {
  if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
      if (oldValue != null) {
          view.removeOnLayoutChangeListener(oldValue);
      }
      if (newValue != null) {
          view.addOnLayoutChangeListener(newValue);
      }
  }
}

Cuando un receptor tiene varios métodos, se debe dividir en varios receptores. Por ejemplo, View.OnAttachStateChangeListener ()
tiene dos métodos: onViewAttachedToWindow() () y onViewDetachedFromWindow() (). Se deben crear dos interfaces para diferenciar
los atributos y los controladores para ellos.

@TargetApi(VERSION_CODES.HONEYCOMB_MR1) 
public interface OnViewDetachedFromWindow {
  void onViewDetachedFromWindow(View v);
}

@TargetApi(VERSION_CODES.HONEYCOMB_MR1)
public interface OnViewAttachedToWindow {
  void onViewAttachedToWindow(View v);
}

Debido a que el cambio de un receptor también afectará al otro, es necesario tener tres adaptadores de vinculación diferentes, uno para
cada atributo y uno para ambos, si ambos se con guran.

@BindingAdapter("android:onViewAttachedToWindow") 
public static void setListener(View view, OnViewAttachedToWindow attached) {
  setListener(view, null, attached);
}

@BindingAdapter("android:onViewDetachedFromWindow")
public static void setListener(View view, OnViewDetachedFromWindow detached) {
  setListener(view, detached, null);
}

@BindingAdapter({"android:onViewDetachedFromWindow", "android:onViewAttachedToWindow"})
public static void setListener(View view, final OnViewDetachedFromWindow detach,
      final OnViewAttachedToWindow attach) {
  if (VERSION.SDK_INT >= VERSION_CODES.HONEYCOMB_MR1) {
      final OnAttachStateChangeListener newListener;
      if (detach == null && attach == null) {
          newListener = null;
      } else {
          newListener = new OnAttachStateChangeListener() {
              @Override
              public void onViewAttachedToWindow(View v) {
                  if (attach != null) {
                      attach.onViewAttachedToWindow(v);
                  }
              }

              @Override
              public void onViewDetachedFromWindow(View v) {
                  if (detach != null) {
                      detach.onViewDetachedFromWindow(v);
                  }
              }
          };
      }
      final OnAttachStateChangeListener oldListener = ListenerUtil.trackListener(view,
newListener, R.id.onAttachStateChangeListener);
              newListener, R.id.onAttachStateChangeListener);
      if (oldListener != null) {
          view.removeOnAttachStateChangeListener(oldListener);
      }
      if (newListener != null) {
          view.addOnAttachStateChangeListener(newListener);
      }
  }
}

El ejemplo anterior es un poco más complicado de lo normal porque el elemento View usa add o remove para el receptor en lugar de un
método establecido para View.OnAttachStateChangeListener (). La clase android.databinding.adapters.ListenerUtil ayuda a
realizar un seguimiento de los receptores previos para que se puedan eliminar en el adaptador de vinculación.

Mediante la anotación de las interfaces OnViewDetachedFromWindow y OnViewAttachedToWindow con


@TargetApi(VERSION_CODES.HONEYCOMB_MR1), el generador de códigos de vinculación de datos determina que el receptor solo se debe
generar cuando se ejecuta en Honeycomb MR1 y en dispositivos nuevos, la misma versión admitida por
addOnAttachStateChangeListener(View.OnAttachStateChangeListener) ().

Convertidores

Conversiones de objetos

Cuando se muestre un objeto de una expresión de vinculación, se elegirá un establecedor de los establecedores automáticos, con
nombre restablecido y personalizados. El objeto se transmitirá a un tipo de parámetro del establecedor elegido.

Esto resulta conveniente para aquellos que usan ObservableMaps para contener datos. Por ejemplo:

<TextView 
 android:text='@{userMap["lastName"]}'
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"/>

userMap muestra un objeto y ese objeto se transmite de forma automática a un tipo de parámetro en el setText(CharSequence) del
establecedor. Cuando pueda surgir alguna confusión con respecto al tipo de parámetro, el desarrollador deberá transmitir la expresión.

Conversión personalizada

A veces las conversiones deben ser automáticas entre tipos especí cos. Por ejemplo, al establecer el fondo:

<View 
 android:background="@{isError ? @color/red : @color/white}"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"/>

Aquí, el fondo toma un elemento Drawable, pero el color es un número entero. Cada vez que se espera un Drawable y se muestra un
número entero, el int se debe convertir en ColorDrawable. Esta conversión se realiza usando un método estático con una anotación
BindingConversion:

@BindingConversion 
public static ColorDrawable convertColorToDrawable(int color) {
 return new ColorDrawable(color);
}

Ten en cuenta que las conversiones solo suceden en el nivel establecedor, de modo que no está permitido combinar tipos como este:

<View 
 android:background="@{isError ? @drawable/error : @color/white}"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"/>

Compatibilidad de Android Studio con la vinculación de datos


Android Studio admite varias funciones de edición de códigos para código de vinculación de datos. Por ejemplo, admite las siguientes
funciones para expresiones de vinculación de datos:

resalte de sintaxis;
marcación de errores de sintaxis del lenguaje de expresión;
compleción de código XML;
referencias, incluidas las de navegación  () (por ejemplo, hacia una declaración) y documentación rápida  ().

Nota: Las matrices y un tipo genérico  (), como la clase android.databinding.Observable, pueden mostrar errores donde no existen.

En el panel Preview se muestran valores predeterminados para expresiones de vinculación de datos si se proporcionan. En el siguiente
ejemplo de extracto de un elemento de un archivo XML de diseño, en el panel Preview se muestra el valor de texto predeterminado
PLACEHOLDER en TextView.

<TextView android:layout_width="wrap_content" 
 android:layout_height="wrap_content"
 android:text="@{user.firstName, default=PLACEHOLDER}"/>

Si debes mostrar un valor predeterminado durante la etapa de diseño de tu proyecto, también puedes usar los atributos de herramientas
en lugar de valores de expresión predeterminados, como se describe en Atributos de diseño de tiempo de diseño  ().
Get started
Learn how to get your development environment ready to work with the Data Binding
Library, including support for data binding code in Android Studio.

The Data Binding Library offers both exibility and broad compatibility—it's a support library,
so you can use it with devices running Android 4.0 (API level 14) or higher.

It's recommended to use the latest Android Plugin for Gradle in your project. However, data
binding is supported on version 1.5.0 and higher. For more information, see how to update
the Android Plugin for Gradle ().

Build environment

To get started with data binding, download the library from the Support Repository in the
Android SDK manager. For more information, see Update the IDE and SDK Tools ().

To con gure your app to use data binding, add the dataBinding element to your
build.gradle le in the app module, as shown in the following example:

android {
...
dataBinding {
enabled = true
}
}

Note: You must con gure data binding for app modules that depend on libraries that use data binding,
even if the app module doesn't directly use data binding.

Android Studio support for data binding

Android Studio supports many of the editing features for data binding code. For example, it
supports the following features for data binding expressions:

Syntax highlighting
Flagging of expression language syntax errors

XML code completion


References, including navigation  () (such as navigate to a declaration) and quick
documentation  ()

Caution: Arrays and a generic type (), such as the Observable () class, might incorrectly display errors.

The Preview pane in Layout Editor displays the default value of data binding expressions, if
provided. For example, the Preview pane displays the my_default value on the TextView
widget declared in the following example:

<TextView android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{user.firstName, default=my_default}"/>

If you need to display a default value only during the design phase of your project, you can
use tools attributes instead of default expression values, as described in Tools Attributes
Reference ().

New data binding compiler for binding classes

The Android Gradle plugin version 3.1.0-alpha06 includes a new data binding compiler
that generates the binding classes. The new compiler incrementally creates the binding
classes, which in most cases speeds up the build process. To learn more about the binding
classes, see Generated binding classes ().

Previous versions of the data binding compiler generated the binding classes in the same
step that compiles your managed code. If your managed code fails to compile, you might
get multiple errors reporting that the binding classes aren't found. The new data binding
compiler prevents these errors by generating the binding classes before the managed
compiler builds your app.

To enable the new data binding compiler, add the following option to your
gradle.properties le:

android.databinding.enableV2=true

You can also enable the new compiler in your gradle command by adding the following
parameter:

-Pandroid.databinding.enableV2=true
Note: The new data binding compiler in the Android Plugin version 3.1 is not backwards compatible. You
need to generate all your binding classes with this feature enabled to take advantage of incremental
compilation. However, the new compiler in the Android Plugin version 3.2 is compatible with binding
classes generated with previous versions. The new compiler in version 3.2 is enabled by default.

The following behavior changes apply when you enable the new data binding compiler:

The Android Gradle plugin generates binding classes for your layouts before
compiling your managed code.
If a layout is included in more than one target resource con guration, the data binding
library uses android.view.View as the default view type for all views that share the
same resource id but not view type.
Binding classes for library modules are compiled and packaged into the
corresponding Android Archive (AAR) le. App modules that depend on those library
modules no longer need to regenerate the binding classes. For more information
about AAR les, see Create an Android Library ().
A module’s binding adapters can no longer change the behavior of adapters of the
module’s dependencies. Binding adapters only affect code in its own module and
consumers of the module.
Layouts and binding expressions
The expression language allows you to write expressions that handle events dispatched by the views. The Data Binding Library
automatically generates the classes required to bind the views in the layout with your data objects.

Data binding layout les are slightly different and start with a root tag of layout followed by a data element and a view root element.
This view element is what your root would be in a non-binding layout le. The following code shows a sample layout le:

<?xml version="1.0" encoding="utf-8"?> 


<layout xmlns:android="http://schemas.android.com/apk/res/android">
 <data>
     <variable name="user" type="com.example.User"/>
 </data>
 <LinearLayout
     android:orientation="vertical"
     android:layout_width="match_parent"
     android:layout_height="match_parent">
     <TextView android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:text="@{user.firstName}"/>
     <TextView android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:text="@{user.lastName}"/>
 </LinearLayout>
</layout>

The user variable within data describes a property that may be used within this layout.

<variable name="user" type="com.example.User" /> 

Expressions within the layout are written in the attribute properties using the "@{}" syntax. Here, the TextView
(https://developer.android.com/reference/android/widget/TextView.html?hl=es-419) text is set to the firstName property of the user variable:

<TextView android:layout_width="wrap_content" 
        android:layout_height="wrap_content"
        android:text="@{user.firstName}" />

Note: Layout expressions should be kept small and simple, as they can't be unit tested and have limited IDE support. In order to simplify layout expressions,
you can use custom binding adapters ().

Data object

Let's assume for now that you have a plain-old object to describe the User entity:

KOTLIN JAVA

data class User(val firstName: String, val lastName: String) 

This type of object has data that never changes. It is common in applications to have data that is read once and never changes thereafter.
It is also possible to use an object that follows a set of conventions, such as the usage of accessor methods in Java, as shown in the
following example:

KOTLIN JAVA

// Not applicable in Kotlin. 


data class User(val firstName: String, val lastName: String)

From the perspective of data binding, these two classes are equivalent. The expression @{user.firstName} used for the android:text
() attribute accesses the firstName eld in the former class and the getFirstName() method in the latter class. Alternatively, it is also
resolved to firstName() if that method exists.
Binding data

A binding class is generated for each layout le. By default, the name of the class is based on the name of the layout le, converting it to
Pascal case and adding the Binding su x to it. The above layout lename is activity_main.xml so the corresponding generated class
is ActivityMainBinding. This class holds all the bindings from the layout properties (for example, the user variable) to the layout's
views and knows how to assign values for the binding expressions.The recommended method to create the bindings is to do it while
in ating the layout, as shown in the following example:

KOTLIN JAVA

override fun onCreate(savedInstanceState: Bundle?) { 


    super.onCreate(savedInstanceState)

    val binding: ActivityMainBinding = DataBindingUtil.setContentView(


            this, R.layout.activity_main)

    binding.user = User("Test", "User")


}

At runtime, the app displays the Test user in the UI. Alternatively, you can get the view using a LayoutInflater
(https://developer.android.com/reference/android/view/LayoutIn ater.html?hl=es-419), as shown in the following example:

KOTLIN JAVA

val binding: ActivityMainBinding = ActivityMainBinding.inflate(getLayoutInflater()) 

If you are using data binding items inside a Fragment (), ListView (), or RecyclerView () adapter, you may prefer to use the inflate() ()
methods of the bindings classes or the DataBindingUtil () class, as shown in the following code example:

KOTLIN JAVA

val listItemBinding = ListItemBinding.inflate(layoutInflater, viewGroup, false) 


// or
val listItemBinding = DataBindingUtil.inflate(layoutInflater, R.layout.list_item, viewGroup, false)

Expression language

Common features

The expression language looks a lot like expressions found in managed code. You can use the following operators and keywords in the
expression language:

Mathematical + - / * %

String concatenation +
Logical && ||

Binary & | ^
Unary + - ! ~

Shift >> >>> <<


Comparison == > < >= <= (Note that < needs to be escaped as &lt;)
instanceof

Grouping ()
Literals - character, String, numeric, null

Cast
Method calls

Field access
Array access []

Ternary operator ?:
Examples:

android:text="@{String.valueOf(index + 1)}" 
android:visibility="@{age > 13 ? View.GONE : View.VISIBLE}"
android:transitionName='@{"image_" + id}'

Missing operations

The following operations are missing from the expression syntax that you can use in managed code:

this

super

new

Explicit generic invocation

Null coalescing operator

The null coalescing operator (??) chooses the left operand if it isn't null or the right if the former is null.

android:text="@{user.displayName ?? user.lastName}" 

This is functionally equivalent to:

android:text="@{user.displayName != null ? user.displayName : user.lastName}" 

Property Reference

An expression can reference a property in a class by using the following format, which is the same for elds, getters, and
ObservableField () objects:

android:text="@{user.lastName}" 

Avoiding null pointer exceptions

Generated data binding code automatically checks for null values and avoid null pointer exceptions. For example, in the expression
@{user.name}, if user is null, user.name is assigned its default value of null. If you reference user.age, where age is of type int, then
data binding uses the default value of 0.

Collections

Common collections, such as arrays, lists, sparse lists, and maps, can be accessed using the [] operator for convenience.

<data> 
  <import type="android.util.SparseArray"/>
  <import type="java.util.Map"/>
  <import type="java.util.List"/>
  <variable name="list" type="List&lt;String>"/>
  <variable name="sparse" type="SparseArray&lt;String>"/>
  <variable name="map" type="Map&lt;String, String>"/>
  <variable name="index" type="int"/>
  <variable name="key" type="String"/>
</data>

android:text="@{list[index]}"

android:text="@{sparse[index]}"

android:text="@{map[key]}"
Note: For the XML to be syntactically correct, you have to escape the < characters. For example: instead of List<String> you have to write
List&lt;String>.

You can also refer to a value in the map using the object.key notation. For example, @{map[key]} in the example above can be replaced
with @{map.key}.

String literals

You can use single quotes to surround the attribute value, which allows you to use double quotes in the expression, as shown in the
following example:

android:text='@{map["firstName"]}' 

It is also possible to use double quotes to surround the attribute value. When doing so, string literals should be surrounded with back
quotes `:

android:text="@{map[`firstName`]}" 

Resources

You can access resources in an expression by using the following syntax:

android:padding="@{large? @dimen/largePadding : @dimen/smallPadding}" 

Format strings and plurals may be evaluated by providing parameters:

android:text="@{@string/nameFormat(firstName, lastName)}" 
android:text="@{@plurals/banana(bananaCount)}"

When a plural takes multiple parameters, all parameters should be passed:


Have an orange
Have %d oranges

android:text="@{@plurals/orange(orangeCount, orangeCount)}"

Some resources require explicit type evaluation, as shown in the following table:

Type Normal reference Expression reference

String[] @array @stringArray

int[] @array @intArray

TypedArray @array @typedArray

Animator @animator @animator

StateListAnimator @animator @stateListAnimator

color int @color @color

ColorStateList @color @colorStateList

Event handling

Data binding allows you to write expression handling events that are dispatched from the views (for example, the onClick() () method).
Event attribute names are determined by the name of the listener method with a few exceptions. For example, View.OnClickListener ()
has a method onClick() (), so the attribute for this event is android:onClick.

There are some specialized event handlers for the click event that need an attribute other than android:onClick to avoid a con ict. You
can use the following attributes to avoid these type of con icts:
Class Listener setter Attribute

SearchView () setOnSearchClickListener(View.OnClickListener) () android:onSearchClick

ZoomControls () setOnZoomInClickListener(View.OnClickListener) () android:onZoomIn

ZoomControls () setOnZoomOutClickListener(View.OnClickListener) () android:onZoomOut

You can use the following mechanisms to handle an event:

Method references (): In your expressions, you can reference methods that conform to the signature of the listener method. When
an expression evaluates to a method reference, Data binding wraps the method reference and owner object in a listener, and sets
that listener on the target view. If the expression evaluates to null, Data binding doesn't create a listener and sets a null listener
instead.
Listener bindings (): These are lambda expressions that are evaluated when the event happens. Data binding always creates a
listener, which it sets on the view. When the event is dispatched, the listener evaluates the lambda expression.

Method references

Events can be bound to handler methods directly, similar to the way android:onClick () can be assigned to a method in an activity. One
major advantage compared to the View () onClick attribute is that the expression is processed at compile time, so if the method doesn't
exist or its signature is incorrect, you receive a compile time error.

The major difference between method references and listener bindings is that the actual listener implementation is created when the
data is bound, not when the event is triggered. If you prefer to evaluate the expression when the event happens, you should use listener
binding ().

To assign an event to its handler, use a normal binding expression, with the value being the method name to call. For example, consider
the following example layout data object:

KOTLIN JAVA

class MyHandlers { 
    fun onClickFriend(view: View) { ... }
}

The binding expression can assign the click listener for a view to the onClickFriend() method, as follows:

<?xml version="1.0" encoding="utf-8"?> 


<layout xmlns:android="http://schemas.android.com/apk/res/android">
 <data>
     <variable name="handlers" type="com.example.MyHandlers"/>
     <variable name="user" type="com.example.User"/>
 </data>
 <LinearLayout
     android:orientation="vertical"
     android:layout_width="match_parent"
     android:layout_height="match_parent">
     <TextView android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:text="@{user.firstName}"
         android:onClick="@{handlers::onClickFriend}"/>
 </LinearLayout>
</layout>

Note: The signature of the method in the expression must exactly match the signature of the method in the listener object.

Listener bindings

Listener bindings are binding expressions that run when an event happens. They are similar to method references, but they let you run
arbitrary data binding expressions. This feature is available with Android Gradle Plugin for Gradle version 2.0 and later.

In method references, the parameters of the method must match the parameters of the event listener. In listener bindings, only your
return value must match the expected return value of the listener (unless it is expecting void). For example, consider the following
presenter class that has the onSaveClick() method:

KOTLIN JAVA

class Presenter { 
    fun onSaveClick(task: Task){}
}

Then you can bind the click event to the onSaveClick() method, as follows:

<?xml version="1.0" encoding="utf-8"?> 


<layout xmlns:android="http://schemas.android.com/apk/res/android">
  <data>
      <variable name="task" type="com.android.example.Task" />
      <variable name="presenter" type="com.android.example.Presenter" />
  </data>
  <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent">
      <Button android:layout_width="wrap_content" android:layout_height="wrap_content"
      android:onClick="@{() -> presenter.onSaveClick(task)}" />
  </LinearLayout>
</layout>

When a callback is used in an expression, data binding automatically creates the necessary listener and registers it for the event. When
the view res the event, data binding evaluates the given expression. As in regular binding expressions, you still get null and thread safety
of data binding while these listener expressions are being evaluated.

In the example above, we haven't de ned the view parameter that is passed to onClick(View) (). Listener bindings provide two choices
for listener parameters: you can either ignore all parameters to the method or name all of them. If you prefer to name the parameters, you
can use them in your expression. For example, the expression above could be written as follows:

android:onClick="@{(view) -> presenter.onSaveClick(task)}" 

Or if you want to use the parameter in the expression, it could work as follows:

KOTLIN JAVA

class Presenter { 
    fun onSaveClick(view: View, task: Task){}
}

android:onClick="@{(theView) -> presenter.onSaveClick(theView, task)}" 

You can use a lambda expression with more than one parameter:

KOTLIN JAVA

class Presenter { 
    fun onCompletedChanged(task: Task, completed: Boolean){}
}

<CheckBox android:layout_width="wrap_content" android:layout_height="wrap_content" 


    android:onCheckedChanged="@{(cb, isChecked) -> presenter.completeChanged(task, isChecked)}" />

If the event you are listening to returns a value whose type isn't void, your expressions must return the same type of value as well. For
example, if you want to listen for the long click event, your expression should return a boolean.

KOTLIN JAVA

class Presenter { 
    fun onLongClick(view: View, task: Task): Boolean { }
}

android:onLongClick="@{(theView) -> presenter.onLongClick(theView, task)}" 


If the expression cannot be evaluated due to null objects, data binding returns the default value for that type. For example, null for
reference types, 0 for int, false for boolean, etc.

If you need to use an expression with a predicate (for example, ternary), you can use void as a symbol.

android:onClick="@{(v) -> v.isVisible() ? doSomething() : void}" 

Avoid complex listeners

Listener expressions are very powerful and can make your code very easy to read. On the other hand, listeners containing complex
expressions make your layouts hard to read and maintain. These expressions should be as simple as passing available data from your UI
to your callback method. You should implement any business logic inside the callback method that you invoked from the listener
expression.

Imports, variables, and includes

The Data Binding Library provides features such as imports, variables, and includes. Imports make easy to reference classes inside your
layout les. Variables allow you to describe a property that can be used in binding expressions. Includes let you reuse complex layouts
across your app.

Imports

Imports allow you to easily reference classes inside your layout le, just like in managed code. Zero or more import elements may be
used inside the data element. The following code example imports the View () class to the layout le:

<data> 
  <import type="android.view.View"/>
</data>

Importing the View (https://developer.android.com/reference/android/view/View.html?hl=es-419) class allows you to reference it from your binding
expressions. The following example shows how to reference the VISIBLE
(https://developer.android.com/reference/android/view/View.html?hl=es-419#VISIBLE) and GONE
(https://developer.android.com/reference/android/view/View.html?hl=es-419#GONE) constants of the View class:

<TextView 
 android:text="@{user.lastName}"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"
 android:visibility="@{user.isAdult ? View.VISIBLE : View.GONE}"/>

Type aliases

When there are class name con icts, one of the classes may be renamed to an alias. The following example renames the View class in
the com.example.real.estate package to Vista:

<import type="android.view.View"/> 
<import type="com.example.real.estate.View"
      alias="Vista"/>

You can use Vista to reference the com.example.real.estate.View and View may be used to reference android.view.View within the
layout le.

Import other classes

Imported types can be used as type references in variables and expressions. The following example shows User and List used as the
type of a variable:

<data> 
  <import type="com.example.User"/>
  <import type="java.util.List"/>
  <variable name="user" type="User"/>
  <variable name="userList" type="List<User>"/>
</data>

Caution: Android Studio doesn't yet handle imports so the autocomplete for imported variables may not work in your IDE. Your app still compiles and you can
work around the IDE issue by using fully quali ed names in your variable de nitions.

You can also use the imported types to cast part of an expression. The following example casts the connection property to a type of
User:

<TextView 
 android:text="@{((User)(user.connection)).lastName}"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"/>

Imported types may also be used when referencing static elds and methods in expressions. The following code imports the
MyStringUtils class and references its capitalize method:

<data> 
  <import type="com.example.MyStringUtils"/>
  <variable name="user" type="com.example.User"/>
</data>

<TextView
 android:text="@{MyStringUtils.capitalize(user.lastName)}"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"/>

Just as in managed code, java.lang.* is imported automatically.

Variables

You can use multiple variable elements inside the data element. Each variable element describes a property that may be set on the
layout to be used in binding expressions within the layout le. The following example declares the user, image, and note variables:

<data> 
  <import type="android.graphics.drawable.Drawable"/>
  <variable name="user" type="com.example.User"/>
  <variable name="image" type="Drawable"/>
  <variable name="note" type="String"/>
</data>

The variable types are inspected at compile time, so if a variable implements Observable () or is an observable collection (), that should
be re ected in the type. If the variable is a base class or interface that doesn't implement the Observable interface, the variables are not
observed.

When there are different layout les for various con gurations (for example, landscape or portrait), the variables are combined. There
must not be con icting variable de nitions between these layout les.

The generated binding class has a setter and getter for each of the described variables. The variables take the default managed code
values until the setter is called—null for reference types, 0 for int, false for boolean, etc.

A special variable named context is generated for use in binding expressions as needed. The value for context is the Context () object
from the root View's getContext() () method. The context variable is overridden by an explicit variable declaration with that name.

Includes

Variables may be passed into an included layout's binding from the containing layout by using the app namespace and the variable name
in an attribute. The following example shows included user variables from the name.xml and contact.xml layout les:

<?xml version="1.0" encoding="utf-8"?> 


<layout xmlns:android="http://schemas.android.com/apk/res/android"
      xmlns:bind="http://schemas.android.com/apk/res-auto">
 <data>
     <variable name="user" type="com.example.User"/>
 </data>
 <LinearLayout
     android:orientation="vertical"
     android:layout_width="match_parent"
     android:layout_height="match_parent">
     <include layout="@layout/name"
         bind:user="@{user}"/>
     <include layout="@layout/contact"
         bind:user="@{user}"/>
 </LinearLayout>
</layout>

Data binding doesn't support include as a direct child of a merge element. For example, the following layout isn't supported:

<?xml version="1.0" encoding="utf-8"?> 


<layout xmlns:android="http://schemas.android.com/apk/res/android"
      xmlns:bind="http://schemas.android.com/apk/res-auto">
 <data>
     <variable name="user" type="com.example.User"/>
 </data>
 <merge><!-- Doesn't work -->
     <include layout="@layout/name"
         bind:user="@{user}"/>
     <include layout="@layout/contact"
         bind:user="@{user}"/>
 </merge>
</layout>
Work with observable data objects
Observability refers to the capability of an object to notify others about changes in its data.
The Data Binding Library allows you to make objects, elds, or collections observable.

Any plain-old object can be used for data binding, but modifying the object doesn't
automatically cause the UI to update. Data binding can be used to give your data objects
the ability to notify other objects, known as listeners, when its data changes. There are
three different types of observable classes: objects (), elds (), and collections ().

When one of these observable data objects is bound to the UI and a property of the data
object changes, the UI is updated automatically.

Observable elds

Some work is involved in creating classes that implement the Observable () interface,
which could not be worth the effort if your classes only have a few properties. In this case,
you can use the generic Observable () class and the following primitive-speci c classes to
make elds observable:

ObservableBoolean ()

ObservableByte ()

ObservableChar ()

ObservableShort ()

ObservableInt ()

ObservableLong ()

ObservableFloat ()

ObservableDouble ()

ObservableParcelable ()

Observable elds are self-contained observable objects that have a single eld. The
primitive versions avoid boxing and unboxing during access operations. To use this
mechanism, create a public final property in the Java programming language or a read-
only property in Kotlin, as shown in the following example:
KOTLIN JAVA

class User { 
    val firstName = ObservableField<String>()
    val lastName = ObservableField<String>()
    val age = ObservableInt()
}

To access the eld value, use the set() () and get() () accessor methods, as follows:

KOTLIN JAVA

user.firstName = "Google" 
val age = user.age

Note: Android Studio 3.1 and higher allow you to replace observable elds with LiveData objects, which
provide additional bene ts to your app. For more information, see Use LiveData to notify the UI about
data changes ().

Observable collections

Some apps use dynamic structures to hold data. Observable collections allow access to
these structures by using a key. The ObservableArrayMap () class is useful when the key is
a reference type, such as String, as shown in the following example:

KOTLIN JAVA

ObservableArrayMap<String, Any>().apply { 
    put("firstName", "Google")
    put("lastName", "Inc.")
    put("age", 17)
}

In the layout, the map can be found using the string keys, as follows:

<data> 
  <import type="android.databinding.ObservableMap"/>
  <variable name="user" type="ObservableMap<String, Object>"/>
</data>

<TextView
  android:text="@{user.lastName}"
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"/>
<TextView
  android:text="@{String.valueOf(1 + (Integer)user.age)}"
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"/>

The ObservableArrayList () class is useful when the key is an integer, as follows:

KOTLIN JAVA

ObservableArrayList<Any>().apply { 
    add("Google")
    add("Inc.")
    add(17)
}

In the layout, the list can be accessed through the indexes, as shown in the following
example:

<data> 
  <import type="android.databinding.ObservableList"/>
  <import type="com.example.my.app.Fields"/>
  <variable name="user" type="ObservableList<Object>"/>
</data>

<TextView
  android:text='@{user[Fields.LAST_NAME]}'
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"/>
<TextView
  android:text='@{String.valueOf(1 + (Integer)user[Fields.AGE])}'
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"/>

Observable objects

A class that implements the Observable () interface allows the registration of listeners that
want to be noti ed of property changes of on the observable object.

The Observable () interface has a mechanism to add and remove listeners, but you must
decide when noti cations are sent. To make development easier, the Data Binding Library
provides the BaseObservable () class, which implements the listener registration
mechanism. The data class that implements BaseObservable is responsible for notifying
when the properties change. This is done by assigning a Bindable () annotation to the
getter and calling the notifyPropertyChanged() () method in the setter, as shown in the
following example:

KOTLIN JAVA

class User : BaseObservable() { 

    @get:Bindable
    var firstName: String = ""
        set(value) {
            field = value
            notifyPropertyChanged(BR.firstName)
        }

    @get:Bindable
    var lastName: String = ""
        set(value) {
            field = value
            notifyPropertyChanged(BR.lastName)
        }
}

Data binding generates a class named BR in the module package which contains the IDs of
the resources used for data binding. The Bindable () annotation generates an entry in the
BR class le during compilation. If the base class for data classes cannot be changed, the
Observable () interface can be implemented using a PropertyChangeRegistry () object to
register and notify listeners e ciently.
Generated binding classes
The Data Binding Library generates binding classes that are used to access the layout's
variables and views. This page shows how to create and customize generated binding
classes.

The generated binding class links the layout variables with the views within the layout. The
name and package of the binding class can be customized (). All generated binding classes
inherit from the ViewDataBinding () class.

A binding class is generated for each layout le. By default, the name of the class is based
on the name of the layout le, converting it to Pascal case and adding the Binding su x to
it. The above layout lename is activity_main.xml so the corresponding generated class
is ActivityMainBinding. This class holds all the bindings from the layout properties (for
example, the user variable) to the layout's views and knows how to assign values for the
binding expressions.

Create a binding object

The binding object should be created soon after in ating the layout to ensure that the view
hierarchy isn't modi ed before it binds to the views with expressions within the layout. The
most common method to bind the object to a layout is to use the static methods on the
binding class. You can in ate the view hierarchy and bind the object to it by using the
inflate() method of the binding class, as shown in the following example:

KOTLIN JAVA

override fun onCreate(savedInstanceState: Bundle?) { 


    super.onCreate(savedInstanceState)

    val binding: MyLayoutBinding = MyLayoutBinding.inflate(layoutInflater)


}

There is an alternate version of the inflate() method that takes a ViewGroup () object in
addition to the LayoutInflater () object , as shown in the following example:

KOTLIN JAVA
 v
val binding: MyLayoutBinding = MyLayoutBinding.inflate(getLayoutInflater(),

If the layout was in ated using a different mechanism, it can be bound separately, as
follows:

KOTLIN JAVA

val binding: MyLayoutBinding = MyLayoutBinding.bind(viewRoot) 

Sometimes the binding type cannot be known in advance. In such cases, the binding can be
created using the DataBindingUtil () class, as demonstrated in the following code
snippet:

KOTLIN JAVA


val viewRoot = LayoutInflater.from(this).inflate(layoutId, parent, attachToPa
val binding: ViewDataBinding? = DataBindingUtil.bind(viewRoot)

If you are using data binding items inside a Fragment (), ListView (), or RecyclerView ()
adapter, you may prefer to use the inflate() () methods of the bindings classes or the
DataBindingUtil () class, as shown in the following code example:

KOTLIN JAVA

fals
val listItemBinding = ListItemBinding.inflate(layoutInflater, viewGroup, 
// or
val listItemBinding = DataBindingUtil.inflate(layoutInflater, R.layout.list_i

Views with IDs

The Data Binding Library creates a immutable eld in the binding class for each view that
has an ID in the layout. For example, the Data Binding Library creates the firstName and
lastName elds of type TextView from the following layout:

<layout xmlns:android="http://schemas.android.com/apk/res/android"> 
 <data>
     <variable name="user" type="com.example.User"/>
 </data>
 <LinearLayout
     android:orientation="vertical"
     android:layout_width="match_parent"
     android:layout_height="match_parent">
     <TextView android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:text="@{user.firstName}"
 android:id="@+id/firstName"/>
     <TextView android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:text="@{user.lastName}"
android:id="@+id/lastName"/>
 </LinearLayout>
</layout>

The library extracts the views including the IDs from the view hierarchy in a single pass.
This mechanism can be faster than calling the findViewById() () method for every view in
the layout.

IDs aren't as necessary as they are without data binding, but there are still some instances
where access to views is still necessary from code.

Variables

The Data Binding Library generates accessor methods for each variable declared in the
layout. For example, the following layout generates setter and getter methods in the binding
class for the user, image, and note variables:

<data> 
 <import type="android.graphics.drawable.Drawable"/>
 <variable name="user" type="com.example.User"/>
 <variable name="image" type="Drawable"/>
 <variable name="note" type="String"/>
</data>

ViewStubs

Unlike normal views, ViewStub () objects start off as an invisible view. When they either are
made visible or are explicitly told to in ate, they replace themselves in the layout by in ating
another layout.

Because the ViewStub essentially disappears from the view hierarchy, the view in the
binding object must also disappear to allow to be claimed by garbage collection. Because
the views are nal, a ViewStubProxy () object takes the place of the ViewStub in the
generated binding class, giving you access to the ViewStub when it exists and also access
to the in ated view hierarchy when the ViewStub has been in ated.

When in ating another layout, a binding must be established for the new layout. Therefore,
the ViewStubProxy must listen to the ViewStub OnInflateListener () and establish the
binding when required. Since only one listener can exist at a given time, the ViewStubProxy
allows you to set an OnInflateListener, which it calls after establishing the binding.

Immediate Binding

When a variable or observable object changes, the binding is scheduled to change before
the next frame. There are times, however, when binding must be executed immediately. To
force execution, use the executePendingBindings() () method.

Advanced Binding

Dynamic Variables

At times, the speci c binding class isn't known. For example, a RecyclerView.Adapter ()
operating against arbitrary layouts doesn't know the speci c binding class. It still must
assign the binding value during the call to the onBindViewHolder() () method.

In the following example, all layouts that the RecyclerView binds to have an item variable.
The BindingHolder object has a getBinding() method returning the ViewDataBinding ()
base class.

KOTLIN JAVA

override fun onBindViewHolder(holder: BindingHolder, position: Int) { 


    item: T = mItems.get(position)
    holder.binding.setVariable(BR.item, item);
    holder.binding.executePendingBindings();
}

Note: The Data Binding Library generates a class named BR in the module package which contains the
IDs of the resources used for data binding. In the example above, the library automatically generates the
BR.item variable.
Background Thread

You can change your data model in a background thread as long as it isn't a collection. Data
binding localizes each variable / eld during evaluation to avoid any concurrency issues.

Custom binding class names

By default, a binding class is generated based on the name of the layout le, starting with
an uppercase letter, removing underscores ( _ ), capitalizing the following letter, and
su xing the word Binding. The class is placed in a databinding package under the
module package. For example, the layout le contact_item.xml generates the
ContactItemBinding class. If the module package is com.example.my.app, then the
binding class is placed in the com.example.my.app.databinding package.

Binding classes may be renamed or placed in different packages by adjusting the class
attribute of the data element. For example, the following layout generates the ContactItem
binding class in the databinding package in the current module:

<data class="ContactItem"> 
  …
</data>

You can generate the binding class in a different package by pre xing the class name with
a period. The following example generates the binding class in the module package:

<data class=".ContactItem"> 
  …
</data>

You can also use the full package name where you want the binding class to be generated.
The following example creates the ContactItem binding class in the com.example
package:

<data class="com.example.ContactItem"> 
  …
</data>
Binding adapters
Binding adapters are responsible for making the appropriate framework calls to set values. One example is setting a property value like
calling the setText() () method. Another example is setting an event listener like calling the setOnClickListener() () method.

The Data Binding Library allows you to specify the method called to set a value, provide your own binding logic, and specify the type of the
returned object by using adapters.

Setting attribute values

Whenever a bound value changes, the generated binding class must call a setter method on the view with the binding expression. You
can allow the Data Binding Library to automatically determine the method, explicitly declare the method, or provide custom logic to select
a method.

Automatic method selection

For an attribute named example, the library automatically tries to nd the method setExample(arg) that accepts compatible types as the
argument. The namespace of the attribute isn't considered, only the attribute name and type are used when searching for a method.

For example, given the android:text="@{user.name}" expression, the library looks for a setText(arg) method that accepts the type
returned by user.getName(). If the return type of user.getName() is String, the library looks for a setText() method that accepts a
String argument. If the expression returns an int instead, the library searches for a setText() method that accepts an int argument.
The expression must return the correct type, you can cast the return value if necessary.

Data binding works even if no attribute exists with the given name. You can then create attributes for any setter by using data binding. For
example, the support class DrawerLayout () doesn't have any attributes, but plenty of setters. The following layout automatically uses the
setScrimColor(int) () and setDrawerListener(DrawerListener) () methods as the setter for the app:scrimColor and
app:drawerListener attributes, respectively:

<android.support.v4.widget.DrawerLayout 
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
  app:scrimColor="@{@color/scrim}"
  app:drawerListener="@{fragment.drawerListener}">

Specify a custom method name

Some attributes have setters that don't match by name. In these situations, an attribute may be associated with the setter using the
BindingMethods () annotation. The annotation is used with a class and can contain multiple BindingMethod () annotations, one for each
renamed method. Binding methods are annotations that can be added to any class in your app. In the following example, the
android:tint attribute is associated with the setImageTintList(ColorStateList) () method, not with the setTint() method:

KOTLIN JAVA

@BindingMethods(value = [ 
    BindingMethod(
        type = android.widget.ImageView::class,
        attribute = "android:tint",
        method = "setImageTintList")])

Most of the time, you don't need to rename setters in Android framework classes. The attributes already have implemented using the
name convention for to automatically nd matching methods.

Provide custom logic

Some attributes need custom binding logic. For example, there is no associated setter for the android:paddingLeft attribute. Instead,
the setPadding(left, top, right, bottom) method is provided. A static binding adapter method with the BindingAdapter ()
annotation allows you to customize how a setter for an attribute is called.
The attributes of the Android framework classes already have BindingAdapter annotations created. For example, the following example
shows the binding adapter for the paddingLeft attribute:

KOTLIN JAVA

@BindingAdapter("android:paddingLeft") 
fun setPaddingLeft(view: View, padding: Int) {
    view.setPadding(padding,
                view.getPaddingTop(),
                view.getPaddingRight(),
                view.getPaddingBottom())
}

The parameter types are important. The rst parameter determines the type of the view that is associated with the attribute. The second
parameter determines the type accepted in the binding expression for the given attribute.

Binding adapters are useful for other types of customization. For example, a custom loader can be called from a worker thread to load an
image.

The binding adapters that you de ne override the default adapters provided by the Android framework when there is a con ict.

You can also have adapters that receive multiple attributes, as shown in the following example:

KOTLIN JAVA

@BindingAdapter("imageUrl", "error") 
fun loadImage(view: ImageView, url: String, error: Drawable) {
    Picasso.get().load(url).error(error).into(view)
}

You can use the adapter in your layout as shown in the following example. Note that @drawable/venueError refers to a resource in your
app. Surrounding the resource with @{} makes it a valid binding expression.

<ImageView app:imageUrl="@{venue.imageUrl}" app:error="@{@drawable/venueError}" /> 

Note: The Data Binding Library ignores custom namespaces for matching purposes.

The adapter is called if both imageUrl and error are used for an ImageView () object and imageUrl is a string and error is a Drawable ()
. If you want the adapter to be called when any of the attributes is set, you can set the optional requireAll () ag of the adapter to false,
as shown in the following example:

KOTLIN JAVA

@BindingAdapter(value = ["imageUrl", "placeholder"], requireAll = false) 


fun setImageUrl(imageView: ImageView, url: String, placeHolder: Drawable) {
    if (url == null) {
        imageView.setImageDrawable(placeholder);
    } else {
        MyImageLoader.loadInto(imageView, url, placeholder);
    }
}

Note: Your binding adapters override the default data binding adapters when there is a con ict.

Binding adapter methods may optionally take the old values in their handlers. A method taking old and new values should declare all old
values for the attributes rst, followed by the new values, as shown in the example below:

KOTLIN JAVA

@BindingAdapter("android:paddingLeft") 
fun setPaddingLeft(view: View, oldPadding: Int, newPadding: Int) {
    if (oldPadding != newPadding) {
        view.setPadding(padding,
                    view.getPaddingTop(),
                    view.getPaddingRight(),
                    view.getPaddingBottom())
    }
}

Event handlers may only be used with interfaces or abstract classes with one abstract method, as shown in the following example:

KOTLIN JAVA

@BindingAdapter("android:onLayoutChange") 
fun setOnLayoutChangeListener(
        view: View,
        oldValue: View.OnLayoutChangeListener?,
        newValue: View.OnLayoutChangeListener?
) {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
        if (oldValue != null) {
            view.removeOnLayoutChangeListener(oldValue)
        }
        if (newValue != null) {
            view.addOnLayoutChangeListener(newValue)
        }
    }
}

Use this event handler in your layout as follows:

<View android:onLayoutChange="@{() -> handler.layoutChanged()}"/> 

When a listener has multiple methods, it must be split into multiple listeners. For example, View.OnAttachStateChangeListener () has
two methods: onViewAttachedToWindow(View) () and onViewDetachedFromWindow(View) (). The library provides two interfaces to
differentiate the attributes and handlers for them:

KOTLIN JAVA

// Translation from provided interfaces in Java: 


@TargetApi(Build.VERSION_CODES.HONEYCOMB_MR1)
interface OnViewDetachedFromWindow {
    fun onViewDetachedFromWindow(v: View)
}

@TargetApi(Build.VERSION_CODES.HONEYCOMB_MR1)
interface OnViewAttachedToWindow {
    fun onViewAttachedToWindow(v: View)
}

Because changing one listener can also affect the other, you need an adapter that works for either attribute or for both. You can set
requireAll () to false in the annotation to specify that not every attribute must be assigned a binding expression, as shown in the
following example:

KOTLIN JAVA

@BindingAdapter( 
        "android:onViewDetachedFromWindow",
        "android:onViewAttachedToWindow",
        requireAll = false
)
fun setListener(view: View, detach: OnViewDetachedFromWindow?, attach: OnViewAttachedToWindow?) {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR1) {
        val newListener: View.OnAttachStateChangeListener?
        newListener = if (detach == null && attach == null) {
            null
        } else {
            object : View.OnAttachStateChangeListener {
                override fun onViewAttachedToWindow(v: View) {
                    attach?.onViewAttachedToWindow(v)
                }

                override fun onViewDetachedFromWindow(v: View) {


                    detach?.onViewDetachedFromWindow(v)
                }
            }
        }

        val oldListener: View.OnAttachStateChangeListener? =


                ListenerUtil.trackListener(view, newListener, R.id.onAttachStateChangeListener)
        if (oldListener != null) {
            view.removeOnAttachStateChangeListener(oldListener)
        }
        if (newListener != null) {
            view.addOnAttachStateChangeListener(newListener)
        }
    }
}

The above example is slightly more complicated than normal because the View () class uses the addOnAttachStateChangeListener() ()
and removeOnAttachStateChangeListener() () methods instead of a setter method for OnAttachStateChangeListener (). The
android.databinding.adapters.ListenerUtil class helps keep track of the previous listeners so that they may be removed in the
binding adapter.

By annotating the interfaces OnViewDetachedFromWindow and OnViewAttachedToWindow with


@TargetApi(VERSION_CODES.HONEYCOMB_MR1), the data binding code generator knows that the listener should only be generated when
running on Android 3.1 (API level 12) and higher, the same version supported by the addOnAttachStateChangeListener() () method.

Object conversions

Automatic object conversion

When an Object () is returned from a binding expression, the library chooses the method used to set the value of the property. The
Object is cast to a parameter type of the chosen method. This behavior is convenient in apps using the ObservableMap () class to store
data, as shown in the following example:

<TextView 
 android:text='@{userMap["lastName"]}'
 android:layout_width="wrap_content"
 android:layout_height="wrap_content" />

Note: You can also refer to a value in the map using the object.key notation. For example, @{userMap["lastName"]} in the example above can be replaced
with @{userMap.lastName}.

The userMap object in the expression returns a value, which is automatically cast to the parameter type found in the
setText(CharSequence) method used to set the value of the android:text attribute. If the parameter type is ambiguous, you must cast
the return type in the expression.

Custom conversions

In some situations, a custom conversion is required between speci c types. For example, the android:background attribute of a view
expects a Drawable (), but the color value speci ed is an integer. The following example shows an attribute that expects a Drawable, but
an integer is provided instead:

<View 
 android:background="@{isError ? @color/red : @color/white}"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"/>

Whenever a Drawable is expected and an integer is returned, the int should be converted to a ColorDrawable (). The conversion can be
done using a static method with a BindingConversion () annotation, as follows:

KOTLIN JAVA

@BindingConversion 
fun convertColorToDrawable(color: Int) = ColorDrawable(color)
However, the value types provided in the binding expression must be consistent. You cannot use different types in the same expression,
as shown in the following example:

<View 
 android:background="@{isError ? @drawable/error : @color/white}"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"/>
Bind layout views to Architecture
Components
The AndroidX library includes the Architecture Components (), which you can use to design
robust, testable, and maintainable apps. The Data Binding Library works seamlessly with
the Architecture Components to further simplify the development of your UI. The layouts in
your app can bind to the data in the Architecture Components, which already help you
manage the UI controllers lifecycle and notify about changes in the data.

This page shows how to incorporate the Architecture Components to your app to further
enhance the bene ts of using the Data Binding Library.

Use LiveData to notify the UI about data changes

You can use LiveData () objects as the data binding source to automatically notify the UI
about changes in the data. For more information about this Architecture Component, see
LiveData Overview ().

Unlike objects that implement Observable ()—such as observable elds ()—LiveData


objects know about the lifecycle of the observers subscribed to the data changes. This
knowledge enables many bene ts, which are explained in The advantages of using
LiveData (). In Android Studio version 3.1 and higher, you can replace observable elds ()
with LiveData objects in your data binding code.

To use a LiveData object with your binding class, you need to specify a lifecycle owner to
de ne the scope of the LiveData object. The following example speci es the activity as the
lifecycle owner after the binding class has been instantiated:

KOTLIN JAVA

class ViewModelActivity : AppCompatActivity() { 


    override fun onCreate(savedInstanceState: Bundle?) {
        // Inflate view and obtain an instance of the binding class.
        val binding: UserBinding = DataBindingUtil.setContentView(this, R.lay

        // Specify the current activity as the lifecycle owner.


        binding.setLifecycleOwner(this)
    }
}
You can use a ViewModel () component, as explained in Use ViewModel to manage UI-
related data (), to bind the data to the layout. In the ViewModel component, you can use the
LiveData object to transform the data or merge multiple data sources. The following
example shows how to transform the data in the ViewModel:

KOTLIN JAVA

class ScheduleViewModel : ViewModel() { 


    val userName: LiveData

    init {
        val result = Repository.userName
        userName = Transformations.map(result) { result -> result.value }
    }
}

Use ViewModel to manage UI-related data

The Data Binding Library works seamlessly with ViewModel () components, which expose
the data that the layout observes and reacts to its changes. Using ViewModel components
with the Data Binding Library allows you to move UI logic out of the layouts and into the
components, which are easier to test. The Data Binding Library ensures that the views are
bound and unbound from the data source when needed. Most of the remaining work
consists in making sure that you're exposing the correct data. For more information about
this Architecture Component, see ViewModel Overview ().

To use the ViewModel component with the Data Binding Library, you must instantiate your
component, which inherits from the Viewmodel () class, obtain an instance of your binding
class, and assign your ViewModel component to a property in the binding class. The
following example shows how to use the component with the library:

KOTLIN JAVA

class ViewModelActivity : AppCompatActivity() {  


    override fun onCreate(savedInstanceState: Bundle?) {
        // Obtain the ViewModel component.
        UserModel userModel = ViewModelProviders.of(getActivity())
                                                  .get(UserModel.class)

        // Inflate view and obtain an instance of the binding class.


        val binding: UserBinding = DataBindingUtil.setContentView(this, R.lay
        // Assign the component to a property in the binding class.
        binding.viewmodel = userModel
    }
}

In your layout, assign the properties and methods of your ViewModel component to the
corresponding views using binding expressions, as shown in the following example:

<CheckBox  
  android:id="@+id/rememberMeCheckBox"
  android:checked="@{viewmodel.rememberMe}"
  android:onCheckedChanged="@{() -> viewmodel.rememberMeChanged()}" />

Use an Observable ViewModel for more control over binding


adapters

You can use a ViewModel () component that implements the Observable () to notify other
app components about changes in the data, similar to how you would use a LiveData ()
object.

There are situations where you might prefer to use a ViewModel () component that
implements the Observable () interface over using LiveData objects, even if you lose the
lifecycle management capabilities of LiveData. Using a ViewModel component that
implements Observable gives you more control over the binding adapters in your app. For
example, this pattern gives you more control over the noti cations when data changes, it
also allows you to specify a custom method to set the value of an attribute in two-way data
binding.

To implement an observable ViewModel component, you must create a class that inherits
from the ViewModel () class and implements the Observable () interface. You can provide
your custom logic when an observer subscribes or unsubscribes to noti cations using the
addOnPropertyChangedCallback() () and removeOnPropertyChangedCallback() ()
methods. You can also provide custom logic that runs when properties change in the
notifyPropertyChanged() () method. The following code example shows how to
implement an observable ViewModel:

KOTLIN JAVA

/** 
 * A ViewModel that is also an Observable,
 * to be used with the Data Binding Library.
 */
open class ObservableViewModel : ViewModel(), Observable {
    private val callbacks: PropertyChangeRegistry = PropertyChangeRegistry()

    override fun addOnPropertyChangedCallback(


            callback: Observable.OnPropertyChangedCallback) {
        callbacks.add(callback)
    }

    override fun removeOnPropertyChangedCallback(


            callback: Observable.OnPropertyChangedCallback) {
        callbacks.remove(callback)
    }

    /**
     * Notifies observers that all properties of this instance have changed.
     */
    fun notifyChange() {
        callbacks.notifyCallbacks(this, 0, null)
    }

    /**
     * Notifies observers that a specific property has changed. The getter fo
     * property that changes should be marked with the @Bindable annotation t
     * generate a field in the BR class to be used as the fieldId parameter.
     *
     * @param fieldId The generated BR id for the Bindable field.
     */
    fun notifyPropertyChanged(fieldId: Int) {
        callbacks.notifyCallbacks(this, fieldId, null)
    }
}
Two-way data binding
Using one-way data binding, you can set a value on an attribute and set a listener that
reacts to a change in that attribute:

<CheckBox 
  android:id="@+id/rememberMeCheckBox"
  android:checked="@{viewmodel.rememberMe}"
  android:onCheckedChanged="@{viewmodel.rememberMeChanged}"
/>

Two-way data binding provides a shortcut to this process:

<CheckBox 
  android:id="@+id/rememberMeCheckBox"
  android:checked="@={viewmodel.rememberMe}"
/>

The @={} notation, which importantly includes the "=" sign, receives data changes to the
property and listen to user updates at the same time.

In order to react to changes in the backing data, you can make your layout variable an
implementation of Observable, usually BaseObservable (), and use a @Bindable ()
annotation, as shown in the following code snippet:

KOTLIN JAVA

class LoginViewModel : BaseObservable { 


    // val data = ...

    @Bindable
    fun getRememberMe(): Boolean {
        return data.rememberMe
    }

    fun setRememberMe(value: Boolean) {


        // Avoids infinite loops.
        if (data.rememberMe != value) {
            data.rememberMe = value

            // React to the change.


            saveData()
            // Notify observers of a new value.
            notifyPropertyChanged(BR.remember_me)
        }
    }
}

Because the bindable property's getter method is called getRememberMe(), the property's
corresponding setter method automatically uses the name setRememberMe().

For more information on using BaseObservable and @Bindable, see Work with observable
data objects ().

Two-way data binding using custom attributes

The platform provides two-way data binding implementations for the most common two-
way attributes () and change listeners, which you can use as part of your app. If you want to
use two-way data binding with custom attributes, you need to work with the
@InverseBindingAdapter () and @InverseBindingMethod () annotations.

For example, if you want to enable two-way data binding on a "time" attribute in a custom
view called MyView, complete the following steps:

1. Annotate the method that sets the initial value and updates when the value changes
using @BindingAdapter:

KOTLIN JAVA

@BindingAdapter("time") 
@JvmStatic fun setTime(view: MyView, newValue: Time) {
    // Important to break potential infinite loops.
    if (view.time != newValue) {
        view.time = newValue
    }
}

2. Annotate the method that reads the value from the view using
@InverseBindingAdapter:

KOTLIN JAVA

@InverseBindingAdapter("time") 
@JvmStatic fun getTime(view: MyView) : Time {
    return view.getTime()
}

At this point, data binding knows what to do when the data changes (it calls the method
annotated with @BindingAdapter ()) and what to call when the view attribute changes (it
calls the InverseBindingListener ()). However, it doesn't know when or how the attribute
changes.

For that, you need to set a listener on the view. It can be a custom listener associated with
your custom view, or it can be a generic event, such as a loss of focus or a text change. Add
the @BindingAdapter annotation to the method that sets the listener for changes on the
property:

KOTLIN JAVA

@BindingAdapter("app:timeAttrChanged") 
@JvmStatic fun setListeners(
        view: MyView,
        attrChange: InverseBindingListener
) {
    // Set a listener for click, focus, touch, etc.
}

The listener includes an InverseBindingListener as a parameter. You use the


InverseBindingListener to tell the data binding system that the attribute has changed.
The system can then start calling the method annotated using @InverseBindingAdapter,
and so on.

Note: Every two-way binding generates a synthetic event attribute. This attribute has the same name as
the base attribute, but it includes the su x "AttrChanged". The synthetic event attribute allows the
library to create a method annotated using @BindingAdapter to associate the event listener to the
appropriate instance of View.

In practice, this listener includes some non-trivial logic, including listeners for one-way data
binding. For an example, see the adapter for the text attribute change,
TextViewBindingAdapter ().

Converters

If the variable that's bound to a View () object needs to be formatted, translated, or changed
somehow before being displayed, it's possible to use a Converter object.
For example, take an EditText object that shows a date:

<EditText 
  android:id="@+id/birth_date"
  android:text="@={Converter.dateToString(viewmodel.birthDate)}"
/>

The viewmodel.birthDate attribute contains a value of type Long, so it needs to be


formatted by using a converter.

Because a two-way expression is being used, there also needs to be an inverse converter to
let the library know how to convert the user-provided string back to the backing data type, in
this case Long. This process is done by adding the @InverseMethod () annotation to one of
the converters and have this annotation reference the inverse converter. An example of this
con guration appears in the following code snippet:

KOTLIN JAVA

object Converter { 
    @InverseMethod("stringToDate")
    fun dateToString(
        view: EditText, oldValue: Long,
        value: Long
    ): String {
        // Converts long to String.
    }

    fun stringToDate(
        view: EditText, oldValue: String,
        value: String
    ): Long {
        // Converts String to long.
    }
}

In nite loops using two-way data binding

Be careful not to introduce in nite loops when using two-way data binding. When the user
changes an attribute, the method annotated using @InverseBindingAdapter is called, and
the value is assigned to the backing property. This, in turn, would call the method annotated
using @BindingAdapter, which would trigger another call to the method annotated using
@InverseBindingAdapter, and so on.
For this reason, it's important to break possible in nite loops by comparing new and old
values in the methods annotated using @BindingAdapter.

Two-way attributes

The platform provides built-in support for two-way data binding when you use the attributes
in the following table. For details on how the platform provides this support, see the
implementations for the corresponding binding adapters:

Class Attribute(s) Binding adapter

AdapterView  () android:selectedItemPosition AdapterViewBindingAdapter ()


android:selection

CalendarView () android:date CalendarViewBindingAdapter ()

CompoundButton () android:checked  () CompoundButtonBindingAdapter ()

DatePicker  () android:year DatePickerBindingAdapter ()


android:month
android:day

NumberPicker () android:value () NumberPickerBindingAdapter ()

RadioButton  () android:checkedButton () RadioGroupBindingAdapter ()

RatingBar () android:rating  () RatingBarBindingAdapter ()

SeekBar () android:progress () SeekBarBindingAdapter ()

TabHost () android:currentTab TabHostBindingAdapter ()

TextView () android:text () TextViewBindingAdapter ()

TimePicker  () android:hour TimePickerBindingAdapter ()


android:minute

Additional resources

The TwoWaySample  () on GitHub presents an end-to-end example of the concepts


discussed on this page.
Handling Lifecycles with Lifecycle-Aware
Components    Part of Android Jetpack ().

Lifecycle-aware components perform actions in response to a change in the lifecycle status


of another component, such as activities and fragments. These components help you
produce better-organized, and often lighter-weight code, that is easier to maintain.

A common pattern is to implement the actions of the dependent components in the


lifecycle methods of activities and fragments. However, this pattern leads to a poor
organization of the code and to the proliferation of errors. By using lifecycle-aware
components, you can move the code of dependent components out of the lifecycle
methods and into the components themselves.

The android.arch.lifecycle () package provides classes and interfaces that let you build
lifecycle-aware components—which are components that can automatically adjust their
behavior based on the current lifecycle state of an activity or fragment.

Note: To import android.arch.lifecycle () into your Android project, see adding components to your
project ().

Most of the app components that are de ned in the Android Framework have lifecycles
attached to them. Lifecycles are managed by the operating system or the framework code
running in your process. They are core to how Android works and your application must
respect them. Not doing so may trigger memory leaks or even application crashes.

Imagine we have an activity that shows the device location on the screen. A common
implementation might be like the following:

KOTLIN JAVA

internal class MyLocationListener( 


        private val context: Context,
        private val callback: (Location) -> Unit
) {

    fun start() {
        // connect to system location service
    }
    fun stop() {
        // disconnect from system location service
    }
}

class MyActivity : AppCompatActivity() {


    private lateinit var myLocationListener: MyLocationListener

    override fun onCreate(...) {


        myLocationListener = MyLocationListener(this) { location ->
            // update UI
        }
    }

    public override fun onStart() {


        super.onStart()
        myLocationListener.start()
        // manage other components that need to respond
        // to the activity lifecycle
    }

    public override fun onStop() {


        super.onStop()
        myLocationListener.stop()
        // manage other components that need to respond
        // to the activity lifecycle
    }
}

Even though this sample looks ne, in a real app, you end up having too many calls that
manage the UI and other components in response to the current state of the lifecycle.
Managing multiple components places a considerable amount of code in lifecycle methods,
such as onStart() () and onStop() (), which makes them di cult to maintain.

Moreover, there's no guarantee that the component starts before the activity or fragment is
stopped. This is especially true if we need to perform a long-running operation, such as
some con guration check in onStart() (). This can cause a race condition where the
onStop() () method nishes before the onStart() (), keeping the component alive longer
than it's needed.

KOTLIN JAVA

class MyActivity : AppCompatActivity() { 


    private lateinit var myLocationListener: MyLocationListener

    override fun onCreate(...) {


        myLocationListener = MyLocationListener(this) { location ->
            // update UI
        }
    }

    public override fun onStart() {


        super.onStart()
        Util.checkUserStatus { result ->
            // what if this callback is invoked AFTER activity is stopped?
            if (result) {
                myLocationListener.start()
            }
        }
    }

    public override fun onStop() {


        super.onStop()
        myLocationListener.stop()
    }

The android.arch.lifecycle () package provides classes and interfaces that help you
tackle these problems in a resilient and isolated way.

Lifecycle

Lifecycle () is a class that holds the information about the lifecycle state of a component
(like an activity or a fragment) and allows other objects to observe this state.

Lifecycle () uses two main enumerations to track the lifecycle status for its associated
component:

Event

The lifecycle events that are dispatched from the framework and the Lifecycle ()
class. These events map to the callback events in activities and fragments.

State

The current state of the component tracked by the Lifecycle () object.


Think of the states as nodes of a graph and events as the edges between these nodes.

A class can monitor the component's lifecycle status by adding annotations to its methods.
Then you can add an observer by calling the addObserver() () method of the Lifecycle ()
class and passing an instance of your observer, as shown in the following example:

KOTLIN JAVA

class MyObserver : LifecycleObserver { 

    @OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
    fun connectListener() {
        ...
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
    fun disconnectListener() {
        ...
    }
}

In the example above, the myLifecycleOwner object implements the LifecycleOwner ()


interface, which is explained in the following section.

LifecycleOwner
LifecycleOwner () is a single method interface that denotes that the class has a
Lifecycle (). It has one method, getLifecycle() (), which must be implemented by the
class. If you're trying to manage the lifecycle of a whole application process instead, see
ProcessLifecycleOwner ().

This interface abstracts the ownership of a Lifecycle () from individual classes, such as
Fragment () and AppCompatActivity (), and allows writing components that work with
them. Any custom application class can implement the LifecycleOwner () interface.

Components that implement LifecycleObserver () work seamlessly with components that


implement LifecycleOwner () because an owner can provide a lifecycle, which an observer
can register to watch.

For the location tracking example, we can make the MyLocationListener class implement
LifecycleObserver () and then initialize it with the activity's Lifecycle () in the
onCreate() () method. This allows the MyLocationListener class to be self-su cient,
meaning that the logic to react to changes in lifecycle status is declared in
MyLocationListener instead of the activity. Having the individual components store their
own logic makes the activities and fragments logic easier to manage.

KOTLIN JAVA

class MyActivity : AppCompatActivity() { 


    private lateinit var myLocationListener: MyLocationListener

    override fun onCreate(...) {


        myLocationListener = MyLocationListener(this, lifecycle) { location -
            // update UI
        }
        Util.checkUserStatus { result ->
            if (result) {
                myLocationListener.enable()
            }
        }
    }
}

A common use case is to avoid invoking certain callbacks if the Lifecycle () isn't in a good
state right now. For example, if the callback runs a fragment transaction after the activity
state is saved, it would trigger a crash, so we would never want to invoke that callback.

To make this use case easy, the Lifecycle () class allows other objects to query the
current state.
KOTLIN JAVA

internal class MyLocationListener( 


        private val context: Context,
        private val lifecycle: Lifecycle,
        private val callback: (Location) -> Unit
) {

    private var enabled = false

    @OnLifecycleEvent(Lifecycle.Event.ON_START)
    fun start() {
        if (enabled) {
            // connect
        }
    }

    fun enable() {
        enabled = true
        if (lifecycle.currentState.isAtLeast(Lifecycle.State.STARTED)) {
            // connect if not connected
        }
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_STOP)
    fun stop() {
        // disconnect if connected
    }
}

With this implementation, our LocationListener class is completely lifecycle-aware. If we


need to use our LocationListener from another activity or fragment, we just need to
initialize it. All of the setup and teardown operations are managed by the class itself.

If a library provides classes that need to work with the Android lifecycle, we recommend
that you use lifecycle-aware components. Your library clients can easily integrate those
components without manual lifecycle management on the client side.

Implementing a custom LifecycleOwner

Fragments and Activities in Support Library 26.1.0 and later already implement the
LifecycleOwner () interface.

If you have a custom class that you would like to make a LifecycleOwner (), you can use
the LifecycleRegistry () class, but you need to forward events into that class, as shown in
the following code example:

KOTLIN JAVA

class MyActivity : Activity(), LifecycleOwner { 

    private lateinit var mLifecycleRegistry: LifecycleRegistry

    override fun onCreate(savedInstanceState: Bundle?) {


        super.onCreate(savedInstanceState)

        mLifecycleRegistry = LifecycleRegistry(this)
        mLifecycleRegistry.markState(Lifecycle.State.CREATED)
    }

    public override fun onStart() {


        super.onStart()
        mLifecycleRegistry.markState(Lifecycle.State.STARTED)
    }

    override fun getLifecycle(): Lifecycle {


        return mLifecycleRegistry
    }
}

Best practices for lifecycle-aware components

Keep your UI controllers (activities and fragments) as lean as possible. They should
not try to acquire their own data; instead, use a ViewModel () to do that, and observe a
LiveData () object to re ect the changes back to the views.

Try to write data-driven UIs where your UI controller’s responsibility is to update the
views as data changes, or notify user actions back to the ViewModel ().
Put your data logic in your ViewModel () class. ViewModel () should serve as the
connector between your UI controller and the rest of your app. Be careful though, it
isn't ViewModel ()'s responsibility to fetch data (for example, from a network). Instead,
ViewModel () should call the appropriate component to fetch the data, then provide
the result back to the UI controller.
Use Data Binding () to maintain a clean interface between your views and the UI
controller. This allows you to make your views more declarative and minimize the
update code you need to write in your activities and fragments. If you prefer to do this
in the Java programming language, use a library like Butter Knife () to avoid boilerplate
code and have a better abstraction.
If your UI is complex, consider creating a presenter  () class to handle UI
modi cations. This might be a laborious task, but it can make your UI components
easier to test.

Avoid referencing a View () or Activity () context in your ViewModel (). If the


ViewModel outlives the activity (in case of con guration changes), your activity leaks
and isn't properly disposed by the garbage collector.

Use cases for lifecycle-aware components

Lifecycle-aware components can make it much easier for you to manage lifecycles in a
variety of cases. A few examples are:

Switching between coarse and ne-grained location updates. Use lifecycle-aware


components to enable ne-grained location updates while your location app is visible
and switch to coarse-grained updates when the app is in the background. LiveData (),
a lifecycle-aware component, allows your app to automatically update the UI when
your user changes locations.
Stopping and starting video buffering. Use lifecycle-aware components to start video
buffering as soon as possible, but defer playback until app is fully started. You can
also use lifecycle-aware components to terminate buffering when your app is
destroyed.
Starting and stopping network connectivity. Use lifecycle-aware components to
enable live updating (streaming) of network data while an app is in the foreground and
also to automatically pause when the app goes into the background.

Pausing and resuming animated drawables. Use lifecycle-aware components to


handle pausing animated drawables when while app is in the background and resume
drawables after the app is in the foreground.

Handling on stop events

When a Lifecycle () belongs to an AppCompatActivity () or Fragment (), the Lifecycle ()


's state changes to CREATED () and the ON_STOP () event is dispatched when the
AppCompatActivity () or Fragment ()'s onSaveInstanceState() () is called.
When a Fragment () or AppCompatActivity ()'s state is saved via onSaveInstanceState()
(), it's UI is considered immutable until ON_START () is called. Trying to modify the UI after
the state is saved is likely to cause inconsistencies in the navigation state of your
application which is why FragmentManager () throws an exception if the app runs a
FragmentTransaction () after state is saved. See commit() () for details.

LiveData () prevents this edge case out of the box by refraining from calling its observer if
the observer's associated Lifecycle () isn't at least STARTED (). Behind the scenes, it calls
isAtLeast() () before deciding to invoke its observer.

Unfortunately, AppCompatActivity ()'s onStop() () method is called after


onSaveInstanceState() (), which leaves a gap where UI state changes are not allowed but
the Lifecycle () has not yet been moved to the CREATED () state.

To prevent this issue, the Lifecycle () class in version beta2 and lower mark the state as
CREATED () without dispatching the event so that any code that checks the current state
gets the real value even though the event isn't dispatched until onStop() () is called by the
system.

Unfortunately, this solution has two major problems:

On API level 23 and lower, the Android system actually saves the state of an activity
even if it is partially covered by another activity. In other words, the Android system
calls onSaveInstanceState() () but it doesn't necessarily call onStop() (). This
creates a potentially long interval where the observer still thinks that the lifecycle is
active even though its UI state can't be modi ed.

Any class that wants to expose a similar behavior to the LiveData () class has to
implement the workaround provided by Lifecycle () version beta 2 and lower.

Note: To make this ow simpler and provide better compatibility with older versions, starting at version
1.0.0-rc1, Lifecycle () objects are marked as CREATED () and ON_STOP () is dispatched when
onSaveInstanceState() () is called without waiting for a call to the onStop() () method. This is unlikely
to impact your code but it is something you need to be aware of as it doesn't match the call order in the
Activity () class in API level 26 and lower.

Additional resources

Try the lifecycle components codelab () and see the Architecture Components BasicSample
(). Lifecyle-aware components are also used in the Sun ower () demo app.
LiveData Overview    Part of Android Jetpack ().

LiveData () is an observable data holder class. Unlike a regular observable, LiveData is lifecycle-aware, meaning it respects the lifecycle
of other app components, such as activities, fragments, or services. This awareness ensures LiveData only updates app component
observers that are in an active lifecycle state.

Note: To import LiveData components into your Android project, see Adding Components to your Project ().

LiveData considers an observer, which is represented by the Observer () class, to be in an active state if its lifecycle is in the STARTED () or
RESUMED () state. LiveData only noti es active observers about updates. Inactive observers registered to watch LiveData () objects aren't
noti ed about changes.

You can register an observer paired with an object that implements the LifecycleOwner () interface. This relationship allows the
observer to be removed when the state of the corresponding Lifecycle () object changes to DESTROYED (). This is especially useful for
activities and fragments because they can safely observe LiveData () objects and not worry about leaks—activities and fragments are
instantly unsubscribed when their lifecycles are destroyed.

For more information about how to use LiveData, see Work with LiveData objects ().

The advantages of using LiveData

Using LiveData provides the following advantages:

Ensures your UI matches your data state

LiveData follows the observer pattern. LiveData noti es Observer () objects when the lifecycle state changes. You can consolidate
your code to update the UI in these Observer objects. Instead of updating the UI every time the app data changes, your observer
can update the UI every time there's a change.

No memory leaks

Observers are bound to Lifecycle () objects and clean up after themselves when their associated lifecycle is destroyed.

No crashes due to stopped activities

If the observer's lifecycle is inactive, such as in the case of an activity in the back stack, then it doesn’t receive any LiveData events.

No more manual lifecycle handling

UI components just observe relevant data and don’t stop or resume observation. LiveData automatically manages all of this since
it’s aware of the relevant lifecycle status changes while observing.

Always up to date data

If a lifecycle becomes inactive, it receives the latest data upon becoming active again. For example, an activity that was in the
background receives the latest data right after it returns to the foreground.

Proper con guration changes

If an activity or fragment is recreated due to a con guration change, like device rotation, it immediately receives the latest available
data.

Sharing resources

You can extend a LiveData () object using the singleton pattern to wrap system services so that they can be shared in your app. The
LiveData object connects to the system service once, and then any observer that needs the resource can just watch the LiveData
object. For more information, see Extend LiveData ().

Work with LiveData objects

Follow these steps to work with LiveData () objects:


1. Create an instance of LiveData to hold a certain type of data. This is usually done within your ViewModel () class.

2. Create an Observer () object that de nes the onChanged() () method, which controls what happens when the LiveData object's
held data changes. You usually create an Observer object in a UI controller, such as an activity or fragment.

3. Attach the Observer object to the LiveData object using the observe() () method. The observe() method takes a
LifecycleOwner () object. This subscribes the Observer object to the LiveData object so that it is noti ed of changes. You usually
attach the Observer object in a UI controller, such as an activity or fragment.

 Note: You can register an observer without an associated LifecycleOwner () object using the observeForever(Observer) () method. In this case,
the observer is considered to be always active and is therefore always noti ed about modi cations. You can remove these observers calling the
removeObserver(Observer) () method.

When you update the value stored in the LiveData object, it triggers all registered observers as long as the attached LifecycleOwner is
in the active state.

LiveData allows UI controller observers to subscribe to updates. When the data held by the LiveData object changes, the UI automatically
updates in response.

Create LiveData objects

LiveData is a wrapper that can be used with any data, including objects that implement Collections (), such as List (). A LiveData ()
object is usually stored within a ViewModel () object and is accessed via a getter method, as demonstrated in the following example:

KOTLIN JAVA

class NameViewModel : ViewModel() { 

    // Create a LiveData with a String


    val currentName: MutableLiveData<String> by lazy {
        MutableLiveData<String>()
    }

    // Rest of the ViewModel...


}

Initially, the data in a LiveData object is not set.

Note: Make sure to store LiveData objects that update the UI in ViewModel objects, as opposed to an activity or fragment, for the following reasons:

To avoid bloated activities and fragments. Now these UI controllers are responsible for displaying data but not holding data state.

To decouple LiveData instances from speci c activity or fragment instances and allow LiveData objects to survive con guration changes.

You can read more about the bene ts and usage of the ViewModel class in the ViewModel guide ().

Observe LiveData objects

In most cases, an app component’s onCreate() () method is the right place to begin observing a LiveData () object for the following
reasons:

To ensure the system doesn’t make redundant calls from an activity or fragment’s onResume() () method.
To ensure that the activity or fragment has data that it can display as soon as it becomes active. As soon as an app component is in
the STARTED () state, it receives the most recent value from the LiveData objects it’s observing. This only occurs if the LiveData
object to be observed has been set.

Generally, LiveData delivers updates only when data changes, and only to active observers. An exception to this behavior is that observers
also receive an update when they change from an inactive to an active state. Furthermore, if the observer changes from inactive to active
a second time, it only receives an update if the value has changed since the last time it became active.

The following sample code illustrates how to start observing a LiveData object:

KOTLIN JAVA
class NameActivity : AppCompatActivity() { 

    private lateinit var mModel: NameViewModel

    override fun onCreate(savedInstanceState: Bundle?) {


        super.onCreate(savedInstanceState)

        // Other code to setup the activity...

        // Get the ViewModel.


        mModel = ViewModelProviders.of(this).get(NameViewModel::class.java)

        // Create the observer which updates the UI.


        val nameObserver = Observer<String> { newName ->
            // Update the UI, in this case, a TextView.
            mNameTextView.text = newName
        }

        // Observe the LiveData, passing in this activity as the LifecycleOwner and the observer.
        mModel.currentName.observe(this, nameObserver)
    }
}

After observe() () is called with nameObserver passed as parameter, onChanged() () is immediately invoked providing the most recent
value stored in mCurrentName. If the LiveData object hasn't set a value in mCurrentName, onChanged() is not called.

Update LiveData objects

LiveData has no publicly available methods to update the stored data. The MutableLiveData () class exposes the setValue(T) () and
postValue(T) () methods publicly and you must use these if you need to edit the value stored in a LiveData () object. Usually
MutableLiveData is used in the ViewModel () and then the ViewModel only exposes immutable LiveData objects to the observers.

After you have set up the observer relationship, you can then update the value of the LiveData object, as illustrated by the following
example, which triggers all observers when the user taps a button:

KOTLIN JAVA

mButton.setOnClickListener { 
    val anotherName = "John Doe"
    mModel.currentName.setValue(anotherName)
}

Calling setValue(T) in the example results in the observers calling their onChanged() () methods with the value John Doe. The example
shows a button press, but setValue() or postValue() could be called to update mName for a variety of reasons, including in response to
a network request or a database load completing; in all cases, the call to setValue() or postValue() triggers observers and updates the
UI.

Note: You must call the setValue(T) () method to update the LiveData object from the main thread. If the code is executed in a worker thread, you can use
the postValue(T) () method instead to update the LiveData object.

Use LiveData with Room

The Room () persistence library supports observable queries, which return LiveData () objects. Observable queries are written as part of a
Database Access Object (DAO).

Room generates all the necessary code to update the LiveData object when a database is updated. The generated code runs the query
asynchronously on a background thread when needed. This pattern is useful for keeping the data displayed in a UI in sync with the data
stored in a database. You can read more about Room and DAOs in the Room persistent library guide ().

Extend LiveData
LiveData considers an observer to be in an active state if the observer's lifecycle is in either the STARTED () or RESUMED () states The
following sample code illustrates how to extend the LiveData () class:

KOTLIN JAVA

class StockLiveData(symbol: String) : LiveData<BigDecimal>() { 


    private val mStockManager = StockManager(symbol)

    private val mListener = { price: BigDecimal ->


        value = price
    }

    override fun onActive() {


        mStockManager.requestPriceUpdates(mListener)
    }

    override fun onInactive() {


        mStockManager.removeUpdates(mListener)
    }
}

The implementation of the price listener in this example includes the following important methods:

The onActive() () method is called when the LiveData object has an active observer. This means you need to start observing the
stock price updates from this method.
The onInactive() () method is called when the LiveData object doesn't have any active observers. Since no observers are
listening, there is no reason to stay connected to the StockManager service.

The setValue(T) () method updates the value of the LiveData instance and noti es any active observers about the change.

You can use the StockLiveData class as follows:

KOTLIN JAVA

override fun onActivityCreated(savedInstanceState: Bundle?) { 


    super.onActivityCreated(savedInstanceState)
    val myPriceListener: LiveData<BigDecimal> = ...
    myPriceListener.observe(this, Observer<BigDecimal> { price: BigDecimal? ->
        // Update the UI.
    })
}

The observe() () method passes the fragment, which is an instance of LifecycleOwner (), as the rst argument. Doing so denotes that
this observer is bound to the Lifecycle () object associated with the owner, meaning:

If the Lifecycle object is not in an active state, then the observer isn't called even if the value changes.
After the Lifecycle object is destroyed, the observer is automatically removed.

The fact that LiveData objects are lifecycle-aware means that you can share them between multiple activities, fragments, and services.
To keep the example simple, you can implement the LiveData class as a singleton as follows:

KOTLIN JAVA

class StockLiveData(symbol: String) : LiveData<BigDecimal>() { 


    private val mStockManager: StockManager = StockManager(symbol)

    private val mListener = { price: BigDecimal ->


        value = price
    }

    override fun onActive() {


        mStockManager.requestPriceUpdates(mListener)
    }

    override fun onInactive() {


        mStockManager.removeUpdates(mListener)
    }
    companion object {
        private lateinit var sInstance: StockLiveData

        @MainThread
        fun get(symbol: String): StockLiveData {
            sInstance = if (::sInstance.isInitialized) sInstance else StockLiveData(symbol)
            return sInstance
        }
    }
}

And you can use it in the fragment as follows:

KOTLIN JAVA

class MyFragment : Fragment() { 

    override fun onActivityCreated(savedInstanceState: Bundle?) {


        StockLiveData.get(symbol).observe(this, Observer<BigDecimal> { price: BigDecimal? ->
            // Update the UI.
        })

    }

Multiple fragments and activities can observe the MyPriceListener instance. LiveData only connects to the system service if one or
more of them is visible and active.

Transform LiveData

You may want to make changes to the value stored in a LiveData () object before dispatching it to the observers, or you may need to
return a different LiveData instance based on the value of another one. The Lifecycle () package provides the Transformations ()
class which includes helper methods that support these scenarios.

Transformations.map() ()

Applies a function on the value stored in the LiveData object, and propagates the result downstream.

KOTLIN JAVA

val userLiveData: LiveData<User> = UserLiveData() 


val userName: LiveData<String> = Transformations.map(userLiveData) {
    user -> "${user.name} ${user.lastName}"
}

Transformations.switchMap() ()

Similar to map(), applies a function to the value stored in the LiveData object and unwraps and dispatches the result downstream.
The function passed to switchMap() must return a LiveData object, as illustrated by the following example:

KOTLIN JAVA

private fun getUser(id: String): LiveData<User> { 


  ...
}
val userId: LiveData<String> = ...
val user = Transformations.switchMap(userId) { id -> getUser(id) }

You can use transformation methods to carry information across the observer's lifecycle. The transformations aren't calculated unless an
observer is watching the returned LiveData object. Because the transformations are calculated lazily, lifecycle-related behavior is
implicitly passed down without requiring additional explicit calls or dependencies.

If you think you need a Lifecycle object inside a ViewModel () object, a transformation is probably a better solution. For example,
assume that you have a UI component that accepts an address and returns the postal code for that address. You can implement the
naive ViewModel for this component as illustrated by the following sample code:
KOTLIN JAVA

class MyViewModel(private val repository: PostalCodeRepository) : ViewModel() { 

    private fun getPostalCode(address: String): LiveData<String> {


        // DON'T DO THIS
        return repository.getPostCode(address)
    }
}

The UI component then needs to unregister from the previous LiveData object and register to the new instance each time it calls
getPostalCode(). In addition, if the UI component is recreated, it triggers another call to the repository.getPostCode() method
instead of using the previous call’s result.

Instead, you can implement the postal code lookup as a transformation of the address input, as shown in the following example:

KOTLIN JAVA

class MyViewModel(private val repository: PostalCodeRepository) : ViewModel() { 


    private val addressInput = MutableLiveData<String>()
    val postalCode: LiveData<String> = Transformations.switchMap(addressInput) {
            address -> repository.getPostCode(address) }

    private fun setInput(address: String) {


        addressInput.value = address
    }
}

In this case, the postalCode eld is de ned as a transformation of the addressInput. As long as your app has an active observer
associated with the postalCode eld, the eld's value is recalculated and retrieved whenever addressInput changes.

This mechanism allows lower levels of the app to create LiveData objects that are lazily calculated on demand. A ViewModel object can
easily obtain references to LiveData objects and then de ne transformation rules on top of them.

Create new transformations

There are a dozen different speci c transformation that may be useful in your app, but they aren’t provided by default. To implement your
own transformation you can you use the MediatorLiveData () class, which listens to other LiveData () objects and processes events
emitted by them. MediatorLiveData correctly propagates its state to the source LiveData object. To learn more about this pattern, see
the reference documentation of the Transformations () class.

Merge multiple LiveData sources

MediatorLiveData () is a subclass of LiveData () that allows you to merge multiple LiveData sources. Observers of MediatorLiveData
objects are then triggered whenever any of the original LiveData source objects change.

For example, if you have a LiveData object in your UI that can be updated from a local database or a network, then you can add the
following sources to the MediatorLiveData object:

A LiveData object associated with the data stored in the database.


A LiveData object associated with the data accessed from the network.

Your activity only needs to observe the MediatorLiveData object to receive updates from both sources. For a detailed example, see the
Addendum: exposing network status () section of the Guide to App Architecture ().

Additional resources

LiveData is used in the Sun ower () demo app.

Also see the Architecture Components BasicSample  ().

For additional information on using LiveData with Snackbar () messages, navigation events, and other events, read this post  ().
Paging library overview    Part of Android Jetpack ().

The Paging Library makes it easier for you to load data gradually and gracefully within your
app's RecyclerView ().

Many apps consume data from a data source that contains a large number of items, but
only display a small portion at a time.

The Paging Library helps your app observe and display a reasonable subset of this data.
This functionality has several advantages:

Data requests consume less network bandwidth and fewer system resources. Users
who have metered or small data plans appreciate such data-conscious apps.
Even during data updates and refreshes, the app continues to respond quickly to user
input.

If your app already includes logic for paging data and displaying lists, we've provided
guidance on how to update your existing app ().

Note: To import the Paging library into your Android project, see Adding Components to your Project ().

This guide provides an overview of how you can use the Paging Library to request and
display data that users want to see while consuming system resources more economically.
For guides speci c to the layers of your app's architecture, see the following related pages:

UI components and considerations ()


Data components and considerations ()

Note: The Paging Library helps you display data in your UI's list containers smoothly, regardless of
whether you use only a device-internal database or you fetch information from your app's backend. To
learn more about how best to use the library based on where your app's data is located, see Support
different data architectures ().

Library architecture

The Paging Library's key component is the PagedList () class, which is a collection that
loads chunks of your app's data, or pages, asynchronously. This class serves as a mediator
between other pieces of your app's architecture:

Data

Each instance of PagedList () loads an up-to-date snapshot of your app's data from
its DataSource (). Data ows from your app's backend or database into the
PagedList object.

The Paging Library supports a variety of app architectures (), including a standalone


database and a database that communicates with a backend server.

To learn more, see Data components and considerations ().

UI

The PagedList () class works with a PagedListAdapter to load items into a


RecyclerView (). These classes work together to fetch and display content as it's
loaded, prefetching out-of-view content and animating content changes.

To learn more, see UI components and considerations ().

The Paging Library implements the observer pattern that's recommended in the guide to
app architecture (). In particular, the core components of the library create an instance of
LiveData<PagedList> () (or the equivalent RxJava2-based classes) that the UI can
observe. Your app's UI can then present content from PagedList () objects as they're
generated, all while respecting your UI controllers' lifecycles ().

Support different data architectures

The Paging Library supports app architectures, including ones where your app is fetching
data only from a backend server, only from an on-device database, or from a combination of
the two sources. This section provides recommendations for each of these cases.

We've provided examples of the recommend patterns to use for different data
architectures. To view them, see the PagingWithNetwork sample  () on GitHub.

Network only

To display data from a backend server, use the synchronous version of the Retro t API  () to
load information into your own custom DataSource object ().
Note: The Paging Library's DataSource () objects don't provide any error handling because different apps
handle and present error UIs in different ways. If an error occurs, defer to your result callback, and retry
the request later. See the PagingWithNetwork sample  () for an example of this behavior.

Database only

Set up your RecyclerView () to observe local storage, preferably using the Room
persistence library (). That way, whenever data is inserted or modi ed in your app's
database, these changes are automatically re ected in the RecyclerView that's displaying
this data.

Network and database

After you've started observing the database, you can listen for when the database is out of
data by using PagedList.BoundaryCallback (). You can then fetch more items from your
network and insert them into the database. If your UI is observing the database, that's all
you need to do.

The following code snippet shows an example usage of a boundary callback:

KOTLIN JAVA

class ConcertViewModel {  
    fun search(query: String): ConcertSearchResult {
        val boundaryCallback =
                ConcertBoundaryCallback(query, myService, myCache)
        // Use a LiveData object to communicate your network's state back
        // to your app's UI, as in the following example. Note that error
        // handling isn't shown in this snippet.
        // val loadingState: LiveData<MyNetworkState> =
        //        boundaryCallback.loadingState
    }
}

class ConcertBoundaryCallback(
        private val query: String,
        private val service: MyService,
        private val cache: MyLocalCache
) : PagedList.BoundaryCallback<Concert>() {
    // Requests initial data from the network, replacing all content currentl
    // in the database.
    override fun onZeroItemsLoaded() {
        requestAndReplaceInitialData(query)
    }

    // Requests additional data from the network, appending the results to th


    // end of the database's existing data.
    override fun onItemAtEndLoaded(itemAtEnd: Concert) {
        requestAndAppendData(query, itemAtEnd.key)
    }
}

To see a more extended example of how a Paging Library solution can fetch data from both
a network and a database, navigate to the Paging codelab () or the PagingWithNetwork
sample  () on GitHub.

Handle network errors

When using a network to fetch or page the data that you're displaying using the Paging
Library, it's important to not treat the network as being either "available" or "unavailable" all
the time, as many connections are intermittent or aky:

A particular server might fail to respond to a network request.


The device might be connected to a network that's slow or weak.

Instead, your app should check each request for failures and recover as gracefully as
possible in cases where the network isn't available. For example, you can provide a "retry"
button for users to select if the data refresh step doesn't work. If an error occurs during the
data paging step, it's best to retry the paging requests automatically.

Update your existing app

If your app already consumes data from a database or a backend source, it's possible to
upgrade directly to functionality that the Paging Library provides. This section shows how
to upgrade an app that has a common existing design.

Custom paging solutions

If you use custom functionality to load small subsets of data from your app's data source,
you can replace this logic with that from the PagedList () class. Instances of PagedList
offer built-in connections to common data sources. These instances also provide adapters
for RecyclerView () objects that you might include in your app's UI.

Data loaded using lists instead of pages

If you use an in-memory list as the backing data structure for your UI's adapter, consider
observing data updates using a PagedList () class if the number of items in the list can
become large. Instances of PagedList can use either LiveData<PagedList> () or
Observable<List> to pass data updates to your app's UI, minimizing load times and
memory usage. Better still, replacing a List () object with a PagedList object in your app
doesn't require any changes to your app's UI structure or data updating logic.

Associate a data cursor with a list view using CursorAdapter

Your app might use a CursorAdapter () to associate data from a Cursor () with a ListView
(). In that case, you usually need to migrate from a ListView to a RecyclerView () as your
app's list UI container, then replace the Cursor component with either Room () or
PositionalDataSource, depending on whether instances of Cursor access a SQLite
database.

In some situations, such as when working with instances of Spinner (), you provide only the
adapter itself. A library then takes the data that's loaded into that adapter and displays the
data for you. In these situations, change the type of your adapter's data to
LiveData<PagedList> (), then wrap this list in an ArrayAdapter () object before attempting
to have a library class in ate these items in a UI.

Load content asynchronously using AsyncListUtil

If you're using AsyncListUtil () objects to load and display groups of information


asynchronously, the Paging Library lets you load data more easily:

Your data doesn't need to be positional. The Paging Library lets you load data directly
from your backend using keys that the network provides.

Your data can be uncountably large. Using the Paging Library, you can load data into
pages until there isn't any data remaining.

You can observe your data more easily. The Paging library can present your data that
your app's ViewModel holds in an observable data structure.
Note: If your existing app accesses a SQLite database, see the section on using the Room persistence
library ().

Database examples

The following code snippets show several possible ways of having all the pieces work
together.

Observing paged data using LiveData

The following code snippet shows all the pieces working together. As concert events are
added, removed, or changed in the database, the content in the RecyclerView () is
automatically and e ciently updated:

KOTLIN JAVA

@Dao 
interface ConcertDao {
    // The Int type parameter tells Room to use a PositionalDataSource
    // object, with position-based loading under the hood.
    @Query("SELECT * FROM concerts ORDER BY date DESC")
    fun concertsByDate(): DataSource.Factory<Int, Concert>
}

class ConcertViewModel(concertDao: ConcertDao) : ViewModel() {


    val concertList: LiveData<PagedList<Concert>> =
            LivePagedListBuilder(
                    concertDao.concertsByDate(), /* page size */ 20).build()
}

class ConcertActivity : AppCompatActivity() {


    public override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        val viewModel = ViewModelProviders.of(this)
                .get(ConcertViewModel::class.java!!)
        val recyclerView = findViewById(R.id.concert_list)
        val adapter = ConcertAdapter()
        viewModel.concertList.observe(this, { pagedList ->
                adapter.submitList(pagedList) })
        recyclerView.setAdapter(adapter)
    }
}
class ConcertAdapter() :
        PagedListAdapter<Concert, ConcertViewHolder>(DIFF_CALLBACK) {
    fun onBindViewHolder(holder: ConcertViewHolder, position: Int) {
        val concert = getItem(position)
        if (concert != null) {
            holder.bindTo(concert)
        } else {
            // Null defines a placeholder item - PagedListAdapter automatical
            // invalidates this row when the actual object is loaded from the
            // database.
            holder.clear()
        }
    }

    companion object {
        private val DIFF_CALLBACK = object :
                DiffUtil.ItemCallback<Concert>() {
            // Concert details may have changed if reloaded from the database
            // but ID is fixed.
            override fun areItemsTheSame(oldConcert: Concert,
                    newConcert: Concert): Boolean =
                    oldConcert.id == newConcert.id

            override fun areContentsTheSame(oldConcert: Concert,


                    newConcert: Concert): Boolean =
                    oldConcert == newConcert
        }
    }
}

Observing paged data using RxJava2

If you prefer using RxJava2  () instead of LiveData (), you can instead create an
Observable or Flowable object:

KOTLIN JAVA

class ConcertViewModel(concertDao: ConcertDao) : ViewModel() { 


    val concertList: Flowable<PagedList<Concert>> =
            RxPagedListBuilder(concertDao.concertsByDate(), /* page size */ 5
                    .buildFlowable(BackpressureStrategy.LATEST)
}

You can then start and stop observing the data using the code in the following snippet:
KOTLIN JAVA

class ConcertActivity : AppCompatActivity() { 


    private lateinit var adapter: ConcertAdapter
    private lateinit var viewModel: ConcertViewModel

    private val disposable = CompositeDisposable()

    public override fun onCreate(savedInstanceState: Bundle?) {


        super.onCreate(savedInstanceState)
        val recyclerView = findViewById(R.id.concert_list)
        viewModel = ViewModelProviders.of(this)
                .get(ConcertViewModel::class.java!!)
        adapter = ConcertAdapter()
        recyclerView.setAdapter(adapter)
    }

    override fun onStart() {


        super.onStart()
        disposable.add(viewModel.concertList.subscribe({
                flowableList -> adapter.submitList(flowableList)
        }))
    }

    override fun onStop() {


        super.onStop()
        disposable.clear()
    }
}

The code for the ConcertDao and ConcertAdapter are the same for an RxJava2  ()-based
solution as they are for a LiveData ()-based solution.

Provide feedback

Share your feedback and ideas with us through these resources:

Issue tracker ()

Report issues so we can x bugs.

G+ community ()

Provide feedback and discuss ideas with other developers.


Additional resources

To learn more about the Paging Library, see the following guides and videos:

Codelab (): Learn how to add the Paging Library to an app, step by step.

PagingWithNetwork sample  (): See how the Paging Library works with a backend API.
Google I/O session (): Watch this video that introduces the Paging Library.
Paging library UI components and
considerations
This guide builds upon the Paging Library overview (), describing how you can present lists
of information to users in your app's UI, particularly when this information changes.

Connect your UI to your view model

You can connect an instance of LiveData<PagedList> () to a PagedListAdapter (), as


shown in the following code snippet:

KOTLIN JAVA

private val adapter = ConcertAdapter() 


private lateinit var viewModel: ConcertViewModel

override fun onCreate(savedInstanceState: Bundle?) {


    viewModel = ViewModelProviders.of(this).get(ConcertViewModel::class.java
    viewModel.concerts.observe(this, Observer { adapter.submitList(it) })
}

As data sources provide new instances of PagedList (), the activity sends these objects to
the adapter. The PagedListAdapter () implementation de nes how updates are computed,
and it automatically handles paging and list di ng. Therefore, your ViewHolder () only
needs to bind to a particular provided item:

KOTLIN JAVA

class ConcertAdapter() : 
        PagedListAdapter<Concert, ConcertViewHolder>(DIFF_CALLBACK) {
    override fun onBindViewHolder(holder: ConcertViewHolder, position: Int)
        val concert: Concert? = getItem(position)

        // Note that "concert" is a placeholder if it's null.


        holder.bindTo(concert)
    }

    companion object {
        private val DIFF_CALLBACK = object :
                DiffUtil.ItemCallback<Concert>() {
            // The ID property identifies when items are the same.
            override fun areItemsTheSame(oldItem: Concert, newItem: Concert)
                    oldItem.id = newItem.id

            // Use the "==" operator to know when an item's content changes.


            // Implement equals(), or write custom data comparison logic here
            override fun areContentsTheSame(
                    oldItem: Concert, newItem: Concert) = oldItem == newItem
        }
    }
}

The PagedListAdapter () handles page load events using a PagedList.Callback () object.


As the user scrolls, the PagedListAdapter calls PagedList.loadAround() () to provide
hints to the underlying PagedList () as to which items it should fetch from the DataSource
().

Note: PagedList () is content-immutable. This means that, although new content can be loaded into an
instance of PagedList, the loaded items themselves cannot change once loaded. As such, if content in a
PagedList updates, the PagedListAdapter () object receives a completely new PagedList that
contains the updated information.

Implement the di ng callback

The preceding sample shows a manual implementation of areContentsTheSame() (),


which compares relevant object elds. You can also compare contents using the
Object.equals() method in Java-based code or the == operator in Kotlin-based code, but
make sure you either implement the equals() method for the object that you're comparing
or use a Kotlin-based data class.

Di ng using a different adapter type

If you choose not to inherit from PagedListAdapter ()—such as when you're using a library
that provides its own adapter—you can still use the Paging Library adapter's di ng
functionality by working directly with an AsyncPagedListDiffer () object.

Provide placeholders in your UI


In cases where you want your UI to display a list before your app has nished fetching data,
you can show placeholder list items to your users. The RecyclerView () handles this case
by setting the list item itself to null temporarily.

Note: By default, the Paging Library enables this placeholder behavior.

Placeholders have the following bene ts:

Support for scrollbars: The PagedList () provides the number of list items to the
PagedListAdapter (). This information allows the adapter to draw a scrollbar that
conveys the full size of the list. As new pages load, the scrollbar doesn't jump
because your list doesn't change size.
No loading spinner necessary: Because the list size is already known, there's no need
to alert users that more items are loading. The placeholders themselves convey that
information.

Before adding support for placeholders, though, keep the following preconditions in mind:

Requires a countable data set: Instances of DataSource () from the Room


persistence library () can e ciently count their items. If you're using a custom local
storage solution or a network-only data architecture (), however, it might be expensive
or even impossible to determine how many items comprise your data set.
Requires adapter to account for unloaded items: The adapter or presentation
mechanism that you use to prepare the list for in ation needs to handle null list items.
For example, when binding data to a ViewHolder (), you need to provide default values
to represent unloaded data.
Requires same size item views size: If list item sizes can change based on their
content, such as social networking updates, crossfading between items doesn't look
good. We strongly suggest disabling placeholders in this case.

Provide feedback

Share your feedback and ideas with us through these resources:

Issue tracker ()

Report issues so we can x bugs.

G+ community ()
Provide feedback and discuss ideas with other developers.

Additional resources

To learn more about the Paging Library, see the following guides and videos:

Codelab (): Learn how to add the Paging Library to an app, step by step.

PagingWithNetwork sample  (): See how the Paging Library works with a backend API.
Google I/O session (): Watch this video that introduces the Paging Library.
Paging library data components and
considerations
This guide builds upon the Paging Library overview (), discussing how you can customize
your app's data-loading solution to meet your app's architecture needs.

Construct an observable list

Typically, your UI code observes a LiveData<PagedList> () object (or, if you're using


RxJava2  (), a Flowable<PagedList> or Observable<PagedList> object), which resides in
your app's ViewModel (). This observable object forms a connection between the
presentation and contents of your app's list data.

In order to create one of these observable PagedList () objects, pass in an instance of


DataSource.Factory () to a LivePagedListBuilder () or RxPagedListBuilder () object. A
DataSource () object loads pages for a single PagedList. The factory class creates new
instances of PagedList in response to content updates, such as database table
invalidations and network refreshes. The Room persistence library () can provide
DataSource.Factory objects for you, or you can build your own ().

The following code snippet shows how to create a new instance of LiveData<PagedList>
() in your app's ViewModel () class using Room's DataSource.Factory ()-building
capabilities:

ConcertDao

KOTLIN JAVA

@Dao 
interface ConcertDao {
    // The Int type parameter tells Room to use a PositionalDataSource
    // object, with position-based loading under the hood.
    @Query("SELECT * FROM concerts ORDER BY date DESC")
    fun concertsByDate(): DataSource.Factory<Int> concertsByDate()
}

ConcertViewModel
KOTLIN JAVA

// The Int type argument corresponds to a PositionalDataSource object. 


val myConcertDataSource : DataSource.Factory<Int, Concert> =
       concertDao.concertsByDate()

val concertList = LivePagedListBuilder(


    myConcertDataSource, /* page size */ 20).build()

De ne your own paging con guration

To further con gure a LiveData<PagedList> () for advanced cases, you can also de ne
your own paging con guration. In particular, you can de ne the following attributes:

Page size (): The number of items in each page.


Prefetch distance (): Given the last visible item in an app's UI, the number of items
beyond this last item that the Paging Library should attempt to fetch in advance. This
value should be several times larger than the page size.
Placeholder presence (): Determines whether the UI displays placeholders for list
items that haven't nished loading yet. For a discussion about the bene ts and
drawbacks of using placeholders, learn how to Provide placeholders in your UI ().

If you'd like more control over when the Paging Library loads a list from your app's
database, pass a custom Executor () object to the LivePagedListBuilder (), as shown in
the following code snippet:

ConcertViewModel

KOTLIN JAVA

val myPagingConfig = PagedList.Config.Builder() 


        .setPageSize(50)
        .setPrefetchDistance(150)
        .setEnablePlaceholders(true)
        .build()

// The Int type argument corresponds to a PositionalDataSource object.


val myConcertDataSource : DataSource.Factory<Int, Concert> =
        concertDao.concertsByDate()

val concertList = LivePagedListBuilder(myConcertDataSource, myPagingConfig)


        .setFetchExecutor(myExecutor)
        .build()

Choose the correct data source type

It's important to connect to the data source that best handles your source data's structure:

Use PageKeyedDataSource () if pages you load embed next/previous keys. For


example, if you're fetching social media posts from the network, you may need to
pass a nextPage token from one load into a subsequent load.
Use ItemKeyedDataSource () if you need to use data from item N to fetch item N+1.
For example, if you're fetching threaded comments for a discussion app, you might
need to pass the ID of the last comment to get the contents of the next comment.
Use PositionalDataSource () if you need to fetch pages of data from any location
you choose in your data store. This class supports requesting a set of data items
beginning from whatever location you select. For example, the request might return
the 20 data items beginning with location 1200.

Notify when data is invalid

When using the Paging Library, it's up to the data layer to notify the other layers of your app
when a table or row has become stale. To do so, call invalidate() () from the DataSource
() class that you've chosen for your app.

Note: Your app's UI can trigger this data invalidation functionality using a swipe to refresh () model.

Build your own data sources

If you use a custom local data solution, or if you load data directly from a network, you can
implement one of the DataSource () subclassses. The following code snippet shows a data
source that's keyed off of a given concert's start time:

KOTLIN JAVA

class ConcertTimeDataSource() : 
        ItemKeyedDataSource<Date, Concert>() {
    override fun getKey(item: Concert) = item.startTime
    override fun loadInitial(
            params: LoadInitialParams<Date>,
            callback: LoadInitialCallback<Concert>) {
        val items = fetchItems(params.key, params.requestedLoadSize)
        callback.onResult(items)
    }

    override fun loadAfter(


            params: LoadParams<Date>,
            callback: LoadCallback<Concert>) {
        val items = fetchItemsAfter(
            date = params.key,
            limit = params.requestedLoadSize)
        callback.onResult(items)
    }
}

You can then load this customized data into PagedList objects by creating a concrete
subclass of DataSource.Factory (). The following code snippet shows how to generate
new instances of the custom data source de ned in the preceding code snippet:

KOTLIN JAVA

class ConcertTimeDataSourceFactory() : 
        DataSource.Factory<Date, Concert>() {
    val sourceLiveData = MutableLiveData<ConcertTimeDataSource>()
    override fun create(): DataSource<Date, Concert> {
        val source = ConcertTimeDataSource()
        sourceLiveData.postValue(source)
        return source
    }
}

Consider how content updates work

As you construct observable PagedList () objects, consider how content updates work. If
you're loading data directly from a Room database () updates get pushed to your app's UI
automatically.

If you are using a paged network API, you typically have a user interaction, such as "swipe to
refresh", serve as a signal for invalidating your current DataSource () and requesting a new
one. This behavior appears in the following code snippet:
KOTLIN JAVA

class ConcertActivity : AppCompatActivity() {  


    override fun onCreate(savedInstanceState: Bundle?) {
        // ...
        concertTimeViewModel.refreshState.observe(this, Observer {
            // Shows one possible way of triggering a refresh operation.
            swipeRefreshLayout.isRefreshing =
                    it == MyNetworkState.LOADING
        })
        swipeRefreshLayout.setOnRefreshListener {
            concertTimeViewModel.invalidateDataSource()
        }
    }
}

class ConcertTimeViewModel(firstConcertStartTime: Date) : ViewModel() {


    val dataSourceFactory = ConcertTimeDataSourceFactory(firstConcertStartTim
    val concertTimeDataSource = dataSourceFactory.create()
    val concertList: LiveData<PagedList<Concert>> =
            LivePagedListBuilder(dataSourceFactory, 20)
                .setFetchExecutor(myExecutor)
                .build()

    fun invalidateDataSource() = concertTimeDataSource.invalidate()


}

Provide mapping between data representations

The Paging Library supports item-based and page-based transformations of items loaded
by a DataSource ().

In the following code snippet, a combination of concert name and concert date is mapped
to a single string containing both the name and date:

KOTLIN JAVA

class ConcertViewModel : ViewModel() { 


    val concertDescriptions : LiveData<PagedList<String>>
        init {
            val factory = database.allConcertsFactory()
                    .map { concert ->
                           concert.name + " - " + concert.date
                    }
            concerts = LivePagedListBuilder(factory, /* page size */ 30).buil
        }
    }
}

This can be useful if you want to wrap, convert, or prepare items after they're loaded.
Because this work is done on the fetch executor, you can do potentially expensive work,
such as reading from disk or querying a separate database.

Note: JOIN queries are always more e cient that requerying as part of map().

Provide feedback

Share your feedback and ideas with us through these resources:

Issue tracker ()

Report issues so we can x bugs.

G+ community ()

Provide feedback and discuss ideas with other developers.

Additional resources

To learn more about the Paging Library, see the following guides and videos:

Codelab (): Learn how to add the Paging Library to an app, step by step.
PagingWithNetwork sample  (): See how the Paging Library works with a backend API.
Google I/O session (): Watch this video that introduces the Paging Library.
Room Persistence Library    Part of Android Jetpack ().

The Room () persistence library provides an abstraction layer over SQLite to allow for more
robust database access while harnessing the full power of SQLite.

The library helps you create a cache of your app's data on a device that's running your app.
This cache, which serves as your app's single source of truth, allows users to view a
consistent copy of key information within your app, regardless of whether users have an
internet connection.

Note: To import Room into your Android project, see adding components to your project ().

Additional resources

For a guide on applying Room's capabilities to your app's data storage persistence solution,
see the Room () training guide.

For a hands-on experience, try the Android Room with a View () and Android Persistence ()
codelabs.

The room persistence library is used in the Sun ower () demo app.

To browse more Room code samples, see the Android Architecture Components samples
 ().
ViewModel Overview    Part of Android Jetpack ().

The ViewModel () class is designed to store and manage UI-related data in a lifecycle
conscious way. The ViewModel () class allows data to survive con guration changes such
as screen rotations.

Note: To import ViewModel () into your Android project, see adding components to your project ().

The Android framework manages the lifecycles of UI controllers, such as activities and
fragments. The framework may decide to destroy or re-create a UI controller in response to
certain user actions or device events that are completely out of your control.

If the system destroys or re-creates a UI controller, any transient UI-related data you store in
them is lost. For example, your app may include a list of users in one of its activities. When
the activity is re-created for a con guration change, the new activity has to re-fetch the list
of users. For simple data, the activity can use the onSaveInstanceState() () method and
restore its data from the bundle in onCreate() (), but this approach is only suitable for
small amounts of data that can be serialized then deserialized, not for potentially large
amounts of data like a list of users or bitmaps.

Another problem is that UI controllers frequently need to make asynchronous calls that may
take some time to return. The UI controller needs to manage these calls and ensure the
system cleans them up after it's destroyed to avoid potential memory leaks. This
management requires a lot of maintenance, and in the case where the object is re-created
for a con guration change, it's a waste of resources since the object may have to reissue
calls it has already made.

UI controllers such as activities and fragments are primarily intended to display UI data,
react to user actions, or handle operating system communication, such as permission
requests. Requiring UI controllers to also be responsible for loading data from a database
or network adds bloat to the class. Assigning excessive responsibility to UI controllers can
result in a single class that tries to handle all of an app's work by itself, instead of
delegating work to other classes. Assigning excessive responsibility to the UI controllers in
this way also makes testing a lot harder.

It's easier and more e cient to separate out view data ownership from UI controller logic.

Implement a ViewModel
Architecture Components provides ViewModel () helper class for the UI controller that is
responsible for preparing data for the UI. ViewModel () objects are automatically retained
during con guration changes so that data they hold is immediately available to the next
activity or fragment instance. For example, if you need to display a list of users in your app,
make sure to assign responsibility to acquire and keep the list of users to a ViewModel (),
instead of an activity or fragment, as illustrated by the following sample code:

KOTLIN JAVA

class MyViewModel : ViewModel() { 


    private lateinit var users: MutableLiveData<List<User>>

    fun getUsers(): LiveData<List<User>> {


        if (!::users.isInitialized) {
            users = MutableLiveData()
            loadUsers()
        }
        return users
    }

    private fun loadUsers() {


        // Do an asynchronous operation to fetch users.
    }
}

You can then access the list from an activity as follows:

KOTLIN JAVA

class MyActivity : AppCompatActivity() { 

    override fun onCreate(savedInstanceState: Bundle?) {


        // Create a ViewModel the first time the system calls an activity's o
        // Re-created activities receive the same MyViewModel instance create

        val model = ViewModelProviders.of(this).get(MyViewModel::class.java)


        model.getUsers().observe(this, Observer<List<User>>{ users ->
            // update UI
        })
    }
}

If the activity is re-created, it receives the same MyViewModel instance that was created by
the rst activity. When the owner activity is nished, the framework calls the ViewModel ()
objects's onCleared() () method so that it can clean up resources.

Caution: A ViewModel () must never reference a view, Lifecycle (), or any class that may hold a
reference to the activity context.

ViewModel () objects are designed to outlive speci c instantiations of views or


LifecycleOwners (). This design also means you can write tests to cover a ViewModel ()
more easily as it doesn't know about view and Lifecycle () objects. ViewModel () objects
can contain LifecycleObservers (), such as LiveData () objects. However ViewModel ()
objects must never observe changes to lifecycle-aware observables, such as LiveData ()
objects. If the ViewModel () needs the Application () context, for example to nd a system
service, it can extend the AndroidViewModel () class and have a constructor that receives
the Application () in the constructor, since Application () class extends Context ().

The lifecycle of a ViewModel

ViewModel () objects are scoped to the Lifecycle () passed to the ViewModelProvider ()


when getting the ViewModel (). The ViewModel () remains in memory until the Lifecycle ()
it's scoped to goes away permanently: in the case of an activity, when it nishes, while in
the case of a fragment, when it's detached.

Figure 1 illustrates the various lifecycle states of an activity as it undergoes a rotation and
then is nished. The illustration also shows the lifetime of the ViewModel () next to the
associated activity lifecycle. This particular diagram illustrates the states of an activity. The
same basic states apply to the lifecycle of a fragment.
You usually request a ViewModel () the rst time the system calls an activity object's
onCreate() () method. The system may call onCreate() () several times throughout the life
of an activity, such as when a device screen is rotated. The ViewModel () exists from when
you rst request a ViewModel () until the activity is nished and destroyed.

Share data between fragments

It's very common that two or more fragments in an activity need to communicate with each
other. Imagine a common case of master-detail fragments, where you have a fragment in
which the user selects an item from a list and another fragment that displays the contents
of the selected item. This case is never trivial as both fragments need to de ne some
interface description, and the owner activity must bind the two together. In addition, both
fragments must handle the scenario where the other fragment is not yet created or visible.

This common pain point can be addressed by using ViewModel () objects. These fragments
can share a ViewModel () using their activity scope to handle this communication, as
illustrated by the following sample code:

KOTLIN JAVA

class SharedViewModel : ViewModel() { 


    val selected = MutableLiveData<Item>()

    fun select(item: Item) {


        selected.value = item
    }
}

class MasterFragment : Fragment() {

    private lateinit var itemSelector: Selector

    private lateinit var model: SharedViewModel

    override fun onCreate(savedInstanceState: Bundle?) {


        super.onCreate(savedInstanceState)
        model = activity?.run {
            ViewModelProviders.of(this).get(SharedViewModel::class.java)
        } ?: throw Exception("Invalid Activity")
        itemSelector.setOnClickListener { item ->
            // Update the UI
        }
    }
}

class DetailFragment : Fragment() {

    private lateinit var model: SharedViewModel

    override fun onCreate(savedInstanceState: Bundle?) {


        super.onCreate(savedInstanceState)
        model = activity?.run {
            ViewModelProviders.of(this).get(SharedViewModel::class.java)
        } ?: throw Exception("Invalid Activity")
        model.selected.observe(this, Observer<Item> { item ->
            // Update the UI
        })
    }
}

Notice that both fragments retrieve the activity that contains them. That way, when the
fragments each get the ViewModelProvider (), they receive the same SharedViewModel
instance, which is scoped to this activity.
This approach offers the following bene ts:

The activity does not need to do anything, or know anything about this
communication.

Fragments don't need to know about each other besides the SharedViewModel
contract. If one of the fragments disappears, the other one keeps working as usual.

Each fragment has its own lifecycle, and is not affected by the lifecycle of the other
one. If one fragment replaces the other one, the UI continues to work without any
problems.

Replacing Loaders with ViewModel

Loader classes like CursorLoader () are frequently used to keep the data in an app's UI in
sync with a database. You can use ViewModel (), with a few other classes, to replace the
loader. Using a ViewModel () separates your UI controller from the data-loading operation,
which means you have fewer strong references between classes.

In one common approach to using loaders, an app might use a CursorLoader () to observe
the contents of a database. When a value in the database changes, the loader automatically
triggers a reload of the data and updates the UI:

Figure 2. Loading data with loaders

ViewModel () works with Room () and LiveData () to replace the loader. The ViewModel ()
ensures that the data survives a device con guration change. Room () informs your
LiveData () when the database changes, and the LiveData (), in turn, updates your UI with
the revised data.
Figure 3. Loading data with ViewModel

Additional resources

This blog post () describes how to use a ViewModel () with a LiveData () to replace an
AsyncTaskLoader ().

As your data grows more complex, you might choose to have a separate class just to load
the data. The purpose of ViewModel () is to encapsulate the data for a UI controller to let the
data survive con guration changes. For information about how to load, persist, and manage
data across con guration changes, see Saving UI States ().

The Guide to Android App Architecture () suggests building a repository class to handle
these functions.

ViewModel () is used in the Android Lifecycles codelab () and the Sun ower () demo app.
Also see the Architecture Components BasicSample  ().
Schedule tasks with WorkManager   
Part of Android Jetpack ().

The WorkManager API makes it easy to specify deferrable, asynchronous tasks and when
they should run. These APIs let you create a task and hand it off to WorkManager to run
immediately or at an appropriate time.

WorkManager chooses the appropriate way to run your task based on such factors as the
device API level and the app state. If WorkManager executes one of your tasks while the
app is running, WorkManager can run your task in a new thread in your app's process. If
your app is not running, WorkManager chooses an appropriate way to schedule a
background task--depending on the device API level and included dependencies,
WorkManager might use JobScheduler (), Firebase JobDispatcher (), or AlarmManager ().
You don't need to write device logic to gure out what capabilities the device has and
choose an appropriate API; instead, you can just hand your task off to WorkManager and let
it choose the best option.

Note: WorkManager is intended for tasks that require a guarantee that the system will run them even if
the app exits, like uploading app data to a server. It is not intended for in-process background work that
can safely be terminated if the app process goes away; for situations like that, we recommend using
ThreadPools ().

Topics

WorkManager basics ()

Use WorkManager to schedule single tasks that run under the circumstances you
choose, or recurring tasks that run at a speci ed interval.

WorkManager advanced features ()

Set up chained sequences of tasks, set up tasks that pass and return values, and set
up named, unique work sequences.

Migrating from Firebase JobDispatcher ()

Update an existing app so it uses WorkManager instead of Firebase JobDispatcher.


WorkManager basics
With WorkManager, you can easily set up a task and hand it off to the system to run under
the conditions you specify.

This overview covers the most basic WorkManager features. In this page, you'll learn how to
set up a task, specify the conditions under which it should run, and hand it off to the
system. You'll also learn how to set up recurring jobs.

For information about more advanced WorkManager features, like job chaining and pass
and return values, see WorkManager advanced features (). There are many more features
available; for full details, see the WorkManager reference documentation ().

Note: To import the WorkManager library into your Android project, see Adding Components to your
Project ().

Classes and concepts

The WorkManager API uses several different classes. In some cases, you'll need to
subclass one of the API classes.

These are the most important WorkManager classes:

Worker (): speci es what task you need to perform. The WorkManager APIs include
an abstract Worker () class. You extend this class and perform the work here.
WorkRequest (): represents an individual task. At a minimum, a WorkRequest () object
speci es which Worker () class should perform the task. However, you can also add
details to the WorkRequest () object, specifying things like the circumstances under
which the task should run. Every WorkRequest () has an autogenerated unique ID; you
can use the ID to do things like cancel a queued task or get the task's state.
WorkRequest () is an abstract class; in your code, you'll be using one of the direct
subclasses, OneTimeWorkRequest () or PeriodicWorkRequest ().
WorkRequest.Builder (): a helper class for creating WorkRequest () objects.
Again, you'd be using one of the subclasses, OneTimeWorkRequest.Builder ()
or PeriodicWorkRequest.Builder ().
Constraints (): speci es restrictions on when the task should run (for example,
"only when connected to the network"). You create the Constraints () object
with Constraints.Builder (), and pass the Constraints () to the
WorkRequest.Builder () before creating the WorkRequest ().

WorkManager (): enqueues and manages the work requests. You pass your
WorkRequest () object to WorkManager () to enqueue the task. WorkManager ()
schedules the task in such a way as to spread out the load on system resources, while
honoring the constraints you specify.

WorkInfo (): contains information about a particular task. The WorkManager ()


provides a LiveData () for each WorkRequest () object. The LiveData () holds a
WorkInfo () object; by observing that LiveData (), you can determine the current
status of the task, and get any returned values after the task nishes.

Typical work ow

Suppose that you're writing a photo library app, and that app needs to periodically
compress its stored images. You want to use the WorkManager APIs to schedule the image
compression. In this case, you don't particularly care when the compression happens; you
want to set up the task and forget about it.

First, you would de ne your Worker () class, and override its doWork() () method. Your
worker class speci es how to perform the operation, but doesn't have any information
about when the task should run.

KOTLIN JAVA

class CompressWorker(context : Context, params : WorkerParameters) 


    : Worker(context, params) {

    override fun doWork(): Result {

        // Do the work here--in this case, compress the stored images.


        // In this example no parameters are passed; the task is
        // assumed to be "compress the whole library."
        myCompress()

        // Indicate success or failure with your return value:


        return Result.success()

        // (Returning Result.retry() tells WorkManager to try this task again


        // later; Result.failure() says not to try again.)
    }

Next, you create a OneTimeWorkRequest () object based on that Worker (), then enqueue the
task with WorkManager ():

KOTLIN JAVA


val compressionWork = OneTimeWorkRequestBuilder<CompressWorker>().build() 
WorkManager.getInstance().enqueue(compressionWork)

WorkManager () chooses an appropriate time to run the task, balancing such considerations
as the load on the system, whether the device is plugged in, and so on. In most cases, if you
don't specify any constraints, WorkManager () runs your task right away. If you need to check
on the task status, you can get a WorkInfo () object by getting a handle to the appropriate
LiveData ()<WorkInfo ()>. For example, if you want to check if the task has nished, you
could use code like this:

KOTLIN JAVA

WorkManager.getInstance().getWorkInfoByIdLiveData(compressionWork.id)  
                .observe(lifecycleOwner, Observer { workInfo ->
                    // Do something with the status
                    if (workInfo != null && workInfo.state.isFinished) {
                        // ...
                    }
                })

For more information about working with LiveData (), see the LiveData overview ().

Task constraints

If you wish, you can specify constraints on when the task should run. For example, you
might want to specify that the task should only run when the device is idle, and connected
to power. In this case, you'd need to create a OneTimeWorkRequest.Builder () object, and
use that builder to create the actual OneTimeWorkRequest ():

KOTLIN JAVA
// Create a Constraints object that defines when the task should run 
val myConstraints = Constraints.Builder()
        .setRequiresDeviceIdle(true)
        .setRequiresCharging(true)
        // Many other constraints are available, see the
        // Constraints.Builder reference
        .build()

// ...then create a OneTimeWorkRequest that uses those constraints


val compressionWork = OneTimeWorkRequestBuilder<CompressWorker>()
        .setConstraints(myConstraints)
        .build()

Then pass the new OneTimeWorkRequest () object to WorkManager.enqueue() (), as before.


WorkManager () considers your constraints when nding a time to run the task.

Canceling a Task

You can cancel a task after you enqueue it. To cancel the task, you need its work ID, which
you can get from the WorkRequest () object. For example, the following code cancels the
compressionWork request from the previous section:

KOTLIN JAVA

val compressionWorkId:UUID = compressionWork.getId() 


WorkManager.getInstance().cancelWorkById(compressionWorkId)

WorkManager () makes its best effort to cancel the task, but this is inherently uncertain--the
task may already be running or nished when you attempt to cancel it. WorkManager () also
provides methods to cancel all tasks in a unique work sequence (), or all tasks with a
speci ed tag (), also on a best-effort basis.

Tagged work

You can group your tasks logically by assigning a tag string to any WorkRequest () object.
To set a tag, call WorkRequest.Builder.addTag(String) (), for example:

KOTLIN JAVA

val cacheCleanupTask = 
        OneTimeWorkRequestBuilder<MyCacheCleanupWorker>()
    .setConstraints(myConstraints)
    .addTag("cleanup")
    .build()

The WorkManager () classes provide several utility methods that let you operate on all tasks
with a particular tag. For example, WorkManager.cancelAllWorkByTag(String) () cancels
all tasks with a particular tag, and WorkManager.getWorkInfosByTagLiveData(String) ()
returns a list of all the WorkInfo () for all tasks with that tag.

Recurring tasks

You might have a task that you need to perform repeatedly. For example, the photo
manager app probably wouldn't compress its photos just once. More likely, it would
examine its shared photos every so often, and see if there are any new or changed images
that need to be compressed. This recurring task could compress the images it nds, or
alternatively, it could re off new "compress this image" tasks when it nds an image that
needs compressing.

To create a recurring task, use the PeriodicWorkRequest.Builder () class to create a


PeriodicWorkRequest () object, then enqueue the PeriodicWorkRequest () the same way
you would a OneTimeWorkRequest () object. For example, suppose we de ned a
PhotoCheckWorker class to identify images that need to be compressed. If you want to run
the inventory task every 12 hours, you would create a PeriodicWorkRequest () object like
this:

KOTLIN JAVA

val photoCheckBuilder =  
        PeriodicWorkRequestBuilder<PhotoCheckWorker>(12, TimeUnit.HOURS)
// ...if you want, you can apply constraints to the builder here...

// Create the actual work object:


val photoCheckWork = photoCheckBuilder.build()
// Then enqueue the recurring task:
WorkManager.getInstance().enqueue(photoCheckWork)

The WorkManager () attempts to run your task at the interval you request, subject to the
constraints you impose and its other requirements.
Advanced WorkManager topics
WorkManager makes it easy to set up and schedule elaborate task requests. You can use
the APIs for scenarios like these:

Chained sequences () of tasks that run in a speci ed order


Unique named sequences (), with rules for what happens if the app launches two
sequences with the same name

Tasks that pass and return values (), including chained tasks where each task passes
arguments to the next task in the chain

Chained tasks

Your app might need to run several tasks in a particular order. WorkManager () allows you to
create and enqueue a work sequence that speci es multiple tasks, and what order they
should run in.

For example, suppose your app has three OneTimeWorkRequest () objects: workA, workB,
and workC. The tasks must be run in that order. To enqueue them, create a sequence with
the WorkManager.beginWith(OneTimeWorkRequest) () method, passing the rst
OneTimeWorkRequest () object; that method returns a WorkContinuation () object, which
de nes a sequence of tasks. Then add the remaining OneTimeWorkRequest () objects, in
order, with WorkContinuation.then(OneTimeWorkRequest) (), and nally, enqueue the
whole sequence with WorkContinuation.enqueue() ():

KOTLIN JAVA

WorkManager.getInstance() 
    .beginWith(workA)
        // Note: WorkManager.beginWith() returns a
        // WorkContinuation object; the following calls are
        // to WorkContinuation methods
    .then(workB)    // FYI, then() returns a new WorkContinuation instance
    .then(workC)
    .enqueue()

The WorkManager () runs the tasks in the requested order, according to each task's speci ed
constraints. If any task returns Result.failure() (), the whole sequence ends.
You can also pass multiple OneTimeWorkRequest () objects to any of the
beginWith(List<OneTimeWorkRequest>) () and then(List<OneTimeWorkRequest>) ()
calls. If you pass several OneTimeWorkRequest () objects to a single method call, the
WorkManager () runs all of those tasks (in parallel) before it runs the rest of the sequence.
For example:

KOTLIN JAVA

WorkManager.getInstance() 
    // First, run all the A tasks (in parallel):
    .beginWith(Arrays.asList(workA1, workA2, workA3))
    // ...when all A tasks are finished, run the single B task:
    .then(workB)
    // ...then run the C tasks (in any order):
    .then(Arrays.asList(workC1, workC2))
    .enqueue()

You can create more complex sequences by joining multiple chains with the
WorkContinuation.combine(List<OneTimeWorkRequest>) () methods. For example,
suppose you want to run a sequence like this:

Figure 1. You can use WorkContinuation () to set up complex chained tasks.

To set up this sequence, create two separate chains, then join them together into a third
one:
KOTLIN JAVA

val chain1 = WorkManager.getInstance() 


    .beginWith(workA)
    .then(workB)
val chain2 = WorkManager.getInstance()
    .beginWith(workC)
    .then(workD)
val chain3 = WorkContinuation
    .combine(Arrays.asList(chain1, chain2))
    .then(workE)
chain3.enqueue()

In this case, WorkManager () runs workA before workB. It also runs workC before workD.
After both workB and workD have nished, WorkManager () runs workE.

Note: While WorkManager () runs each of the subchains in order, there is no guarantee about how the
tasks in chain1 might overlap with those in chain2. For example, workB might run before or after workC,
or they might run at the same time. The only promise is that the tasks within each subchain will run in
order; that is, workB does not start until after workA has nished.

There are a number of variants of the WorkContinuation () methods that provide


shorthands for particular situations. For details, see the WorkContinuation () reference.

Unique work sequences

You can create a unique work sequence, by beginning the sequence with a call to
beginUniqueWork(String, ExistingWorkPolicy, OneTimeWorkRequest) () instead of
beginWith(OneTimeWorkRequest) (). Each unique work sequence has a name; the
WorkManager () only permits one work sequence with that name at a time. When you create
a new unique work sequence, you specify what WorkManager () should do if there's already
an un nished sequence with the same name:

Cancel the existing sequence and REPLACE () it with the new one

KEEP () the existing sequence and ignore your new request

APPEND () your new sequence to the existing one, running the new sequence's rst
task after the existing sequence's last task nishes

Unique work sequences can be useful if you have a task that shouldn't be enqueued
multiple times. For example, if your app needs to sync its data to the network, you might
enqueue a sequence named "sync", and specify that your new task should be ignored if
there's already a sequence with that name. Unique work sequences can also be useful if
you need to gradually build up a long chain of tasks. For example, a photo editing app might
let users undo a long chain of actions. Each of those undo operations might take a while,
but they have to be performed in the correct order. In this case, the app could create an
"undo" chain and append each undo operation to the chain as needed.

Input parameters and returned values

For greater exibility, you can pass arguments to your tasks and have the tasks return
results. Passed and returned values are key-value pairs. To pass an argument to a task, call
the WorkRequest.Builder.setInputData(Data) () method before you create the
WorkRequest () object. That method takes a Data () object, which you create with
Data.Builder (). The Worker () class can access those arguments by calling
Worker.getInputData() (). To output a return value, the task should include it in the
Result () (for example, returning Result.success(Data) (). You can get the output by
observing the task's WorkInfo ().

For example, suppose you have a Worker () class that performs a time-consuming
calculation. The following code shows what the Worker () class would look like:

KOTLIN JAVA

// Define the parameter keys: 


const val KEY_X_ARG = "X"
const val KEY_Y_ARG = "Y"
const val KEY_Z_ARG = "Z"

// ...and the result key:


const val KEY_RESULT = "result"

// Define the Worker class:


class MathWorker(context : Context, params : WorkerParameters)
    : Worker(context, params)  {

    override fun doWork(): Result {


        val x = inputData.getInt(KEY_X_ARG, 0)
        val y = inputData.getInt(KEY_Y_ARG, 0)
        val z = inputData.getInt(KEY_Z_ARG, 0)

        // ...do the math...


        val result = myCrazyMathFunction(x, y, z);
        //...set the output, and we're done!
        val output: Data = mapOf(KEY_RESULT to result).toWorkData()

        return Result.success(output)
    }
}

To create the work and pass the arguments, you'd use code like this:

KOTLIN JAVA

val myData: Data = mapOf("KEY_X_ARG" to 42, 


                       "KEY_Y_ARG" to 421,
                       "KEY_Z_ARG" to 8675309)
                     .toWorkData()

// ...then create and enqueue a OneTimeWorkRequest that uses those arguments


val mathWork = OneTimeWorkRequestBuilder<MathWorker>()
        .setInputData(myData)
        .build()
WorkManager.getInstance().enqueue(mathWork)

The returned value would be available in the task's WorkInfo ():

KOTLIN JAVA

WorkManager.getInstance().getWorkInfoByIdLiveData(mathWork.id) 
        .observe(this, Observer { info ->
            if (info != null && info.state.isFinished) {
                val myResult = info.outputData.getInt(KEY_RESULT,
                      myDefaultValue)
                // ... do something with the result ...
            }
        })

If you chain tasks, the outputs from one task are available as inputs to the next task in the
chain. If it's a simple chain, with a single OneTimeWorkRequest () followed by another single
OneTimeWorkRequest (), the rst task returns its result by calling Result.success(Data) (),
and the next task fetches that result by calling getInputData() (). If the chain is more
complicated—for example, because several tasks all send output to a single following task
—you can de ne an InputMerger () on the OneTimeWorkRequest.Builder () to specify
what should happen if different tasks return an output with the same key.
Saving UI States
Preserving and restoring an activity’s UI state in a timely fashion across system-initiated
activity or application destruction is a crucial part of the user experience. In these cases the
user expects the UI state to remain the same, but the system destroys the activity and any
state stored in it.

To bridge the gap between user expectation and system behavior, use a combination of
ViewModel () objects, the onSaveInstanceState() () method, and/or local storage to
persist the UI state across such application and activity instance transitions. Deciding how
to combine these options depends on the complexity of your UI data, use cases for your
app, and consideration of speed of retrieval versus memory usage.

Regardless of which approach you take, you should ensure your app meets users
expectations with respect to to their UI state, and provides a smooth, snappy UI (avoids lag
time in loading data into the UI, especially after frequently occurring con guration changes,
like rotation). In most cases you should use both ViewModel and onSaveInstanceState().

This page discusses user expectations about UI state, options available for preserving
state, the tradeoffs and limitations of each.

User expectations and system behavior

Depending upon the action a user takes, they either expect that activity state to be cleared
or the state to be preserved. In some cases the system automatically does what is
expected by the user. In other cases the system does the opposite of what the user
expects.

User-initiated UI state dismissal

The user expects that when they start an activity, the transient UI state of that activity will
remain the same until the user completely dismisses the activity. The user can completely
dismiss an activity by:

pressing the back button


swiping the activity off of the Overview (Recents) screen
navigating up from the activity
killing the app from Settings screen
completing some sort of " nishing" activity (which is backed by Activity. nish())

The user's assumption in these complete dismissal cases is that they have permanently
navigated away from the activity, and if they re-open the activity they expect the activity to
start from a clean state. The underlying system behavior for these dismissal scenarios
matches the user expectation - the activity instance will get destroyed and removed from
memory, along with any state stored in it and any saved instance state record associated
with the activity.

There are some exceptions to this rule about complete dismissal -- for example a user
might expect a browser to take them to the exact webpage they were looking at before they
exited the browser using the back button.

System-initiated UI state dismissal

A user expects an activity’s UI state to remain the same throughout a con guration change,
such as rotation or switching into multi-window mode. However, by default the system
destroys the activity when such a con guration change occurs, wiping away any UI state
stored in the activity instance. To learn more about device con gurations, see the
Con guration reference page (). Note, it is possible (though not recommended) to override
the default behavior for con guration changes. See Handling the Con guration Change
Yourself () for more details.

A user also expects your activity's UI state to remain the same if they temporarily switch to
a different app and then come back to your app later. For example, the user performs a
search in your search activity and then presses the home button or answers a phone call -
when they return to the search activity they expect to nd the search keyword and results
still there, exactly as before.

In this scenario, your app is placed in the background the system does its best to keep your
app process in memory. However, the system may destroy the application process while
the user is away interacting with other apps. In such a case, the activity instance is
destroyed, along with any state stored in it. When the user relaunches the app, the activity is
unexpectedly in a clean state. To learn more about process death, see Processes and
Application Lifecycle ().

Options for preserving UI state


When the user's expectations about UI state do not match default system behavior, you
must save and restore the user's UI state to ensure that the system-initiated destruction is
transparent to the user.

Each of the options for preserving UI state vary along the following dimensions that impact
the user experience:

ViewModel Saved instance state Persistent storage

Storage location in memory serialized to disk on disk or network

Survives Yes Yes Yes


con guration
change

Survives system- No Yes Yes


initiated process
death

Survives user No No Yes


complete activity
dismissal/onFinish()

Data limitations complex objects are ne, only for primitive types and only limited by disk space or
but space is limited by simple, small objects such cost / time of retrieval from
available memory as String the network resource

Read/write time quick (memory access slow (requires slow (requires disk access or
only) serialization/deserializationnetwork transaction)
and disk access)

Use ViewModel to handle con guration changes

ViewModel is ideal for storing and managing UI-related data while the user is actively using
the application. It allows quick access to UI data and helps you avoid refetching data from
network or disk across rotation, window resizing, and other commonly occurring
con guration changes. To learn how to implement a ViewModel, see the ViewModel guide
().

ViewModel retains the data in memory, which means it is cheaper to retrieve than data from
the ViewModel than disk or the network. A ViewModel is associated with an activity (or
some other lifecycle owner) - it stays in memory during a con guration change and the
system automatically associates the ViewModel with the new activity instance that results
from the con guration change.
ViewModels are automatically destroyed by the system when your user backs out of your
activity or fragment or if you call nish(), which means the state will be cleared as the user
expects in these scenarios.

Unlike saved instance state, ViewModels are destroyed during a system-initiated process
death. This is why you should use ViewModel objects in combination with
onSaveInstanceState() (or some other disk persistence), stashing identi ers in
savedInstanceState to help view models reload the data after system death.

If you already have an in-memory solution in place for storing your UI state across
con guration changes, you may not need to use ViewModel.

Use onSaveInstanceState() as backup to handle system-


initiated process death

The onSaveInstanceState() () callback stores data needed to reload the state of a UI


controller, such as an activity or a fragment, if the system destroys and later recreates that
controller. To learn how to implement saved instance state, see Saving and restoring
activity state in the Activity Lifecycle guide ().

Saved instance state bundles persist both con guration changes and process death, but
are limited by amount of storage and speed because onSavedInstanceState() serializes
data to disk. Serialization can consume a lot of memory if the objects being serialized are
complicated. Because this process happens on the main thread during a con guration
change, serialization can cause dropped frames and visual stutter if it takes too long.

Do not use store onSavedInstanceState() to store large amounts of data, such as bitmaps,
nor complex data structures that require lengthy serialization or deserialization. Instead,
store only primitive types and simple, small objects such as String. As such, use
onSaveInstanceState() to store a minimal amount of data necessary, such as an ID, to re-
create the data necessary to restore the UI back to its previous state should the other
persistence mechanisms fail. Most apps should implement onSaveInstanceState() to
handle system-initiated process death.

Depending on your app's uses cases, you might not need to use onSaveInstanceState() ()
at all. For example, a browser might take the user back to the exact webpage they were
looking at before they exited the browser. If your activity behaves this way, you can forego
using onSaveInstanceState() () and instead persist everything locally.

Additionally, when you open an activity from an intent, the bundle of extras is delivered to
the activity both when the con guration changes and when the system restores the activity.
If a piece of UI state data, such as a search query, were passed in as an intent extra when
the activity was launched, you could use the extras bundle instead of the
onSaveInstanceState() bundle. To learn more about intent extras, see Intent and Intent
Filters ().

In either of these scenarios, you should still use a ViewModel () to avoid wasting cycles
reloading data from the database during a con guration change.

In cases where the UI data to preserve is simple and lightweight, you might use
onSaveInstanceState() () alone to preserve your state data.

Use local persistence to handle process death for complex or


large data

Persistent local storage, such as a database or shared preferences, will survive for as long
as your application is installed on the user’s device (unless the user clears the data for your
app). While such local storage survives system-initiated activity and application process
death, it can be expensive to retrieve because it will have to be read from local storage in to
memory. Often this persistent local storage may already be a part of your application
architecture to store all data you don’t want to lose if you open and close the activity.

Neither ViewModel nor saved instance state are long-term storage solutions and thus are
not replacements for local storage, such as a database. Instead you should use these
mechanisms for temporarily storing transient UI state only and use persistent storage for
other app data. See Guide to App Architecture () for more details about how to leverage
local storage to persist your app model data long term (e.g. across restarts of the device).

Managing UI state: divide and conquer

You can e ciently save and restore UI state by dividing the work among the various types
of persistence mechanisms. In most cases, each of these mechanisms should store a
different type of data used in the activity, based on the tradeoffs of data complexity, access
speed, and lifetime:

Local persistence: Stores all data you don’t want to lose if you open and close the
activity.
Example: A collection of song objects, which could include audio les and
metadata.
ViewModel (): Stores in memory all the data needed to display the associated UI
Controller.
Example: The song objects of the most recent search and the most recent
search query.
onSaveInstanceState() (): Stores a small amount of data needed to easily reload
activity state if the system stops and then recreates the UI Controller. Instead of
storing complex objects here, persist the complex objects in local storage and store a
unique ID for these objects in onSaveInstanceState() ().

Example: Storing the most recent search query.

As an example, consider an activity that allows you to search through your library of songs.
Here’s how different events should be handled:

When the user adds a song, the ViewModel () immediately delegates persisting this data
locally. If this newly added song is something that should be shown in the UI, you should
also update the data in the ViewModel () object to re ect the addition of the song.
Remember to do all database inserts off of the main thread.

When the user searches for a song, whatever complex song data you load from the
database for the UI Controller should be immediately stored in the ViewModel () object. You
should also save the search query itself in the ViewModel () object.

When the activity goes into the background, the system calls onSaveInstanceState() ().
You should save the search query in the onSaveInstanceState() () bundle. This small
amount of data is easy to save. It’s also all the information you need to get the activity back
into its current state.

Restoring complex states: reassembling the pieces

When it is time for the user to return to the activity, there are two possible scenarios for
recreating the activity:

The activity is recreated after having been stopped by the system. The activity has the
query saved in an onSaveInstanceState() () bundle, and should pass the query to
the ViewModel (). The ViewModel () sees that it has no search results cached, and
delegates loading the search results, using the given search query.
The activity is created after a con guration change. The activity has the query saved
in an onSaveInstanceState() () bundle, and the ViewModel () already has the search
results cached. You pass the query from the onSaveInstanceState() () bundle to the
ViewModel (), which determines that it already has loaded the necessary data and that
it does not need to re-query the database.

Note: When an activity is initially created, the onSaveInstanceState() () bundle contains no data, and
the ViewModel () object is empty. When you create the ViewModel () object, you pass an empty query,
which tells the ViewModel () object that there’s no data to load yet. Therefore, the activity starts in an
empty state.

You might also like