@@ -17,7 +17,7 @@ This sample contains two screens: a list of products and a detail view, that sho
#### Presentation layer
The presentation layer consists of the following components:
* A main activity that handles navigation.
* A main activity that handles navigation.
* A fragment to display the list of products.
* A fragment to display a product review.
...
...
@@ -53,48 +53,22 @@ The app uses a Model-View-ViewModel (MVVM) architecture for the presentation lay
The database is created using Room and it has two entities: a `ProductEntity` and a `CommentEntity` that generate corresponding SQLite tables at runtime.
Room populates the database asynchronously on first use. The `DatabaseCreator` class is responsible for creating the database and tables, and populating them with sample product and review data. This is done on the first use of the database, with the help of an `AsyncTask`. To simulate low-performance, an artificial delay is added. To let other components know when the data has finished populating, the `DatabaseCreator` exposes a `LiveData` object..
Room populates the database asynchronously when it's created, via the `RoomDatabase#Callback`. To simulate low-performance, an artificial delay is added. To let
other components know when the data has finished populating, the `AppDatabase` exposes a
`LiveData` object..
To access the data and execute queries, you use a [Data Access Object](https://developer.android.com/topic/libraries/architecture/room.html#daos)(DAO). For example, a product is loaded with the following query:
```
```java
@Query("select * from products where id = :productId")
LiveData<ProductEntity>loadProduct(intproductId);
```
Queries that return a `LiveData` object can be observed, so when a change in one of the affected tables is detected, `LiveData` delivers a notification of that change to the registered observers.
#### Transformations
Fragments don't observe the database directly, they only interact with ViewModel objects. A ViewModel observes database queries as well as the `DatabaseCreator`, which exposes whether the database is created or not.
For the purpose of the sample, the database is deleted and re-populated each time the app is started, so the app needs to wait until this process is finished. This is solved with a **Transformation**:
Whenever `databaseCreated` changes, `mObservableProducts` will get a new value, either an `ABSENT``LiveData` or the list of products. The database will be observed with the same scope as `mObservableProducts`.
Note that the first time a LiveData object is observed, the current value is emitted and `onChanged` is called.
The following diagram shows the general structure of the sample:
Exercise for the reader: try to apply a transformation to the list of products in the ViewModel
before they are delivered to the fragment. (hint: `Transformations.Map`).
The `DataRepository` exposes the data to the UI layer. To ensure that the UI uses the list of products only after the database has been pre-populated, a [`MediatorLiveData`](https://developer.android.com/reference/android/arch/lifecycle/MediatorLiveData.html) object is used. This
observes the changes of the list of products and only forwards it when the database is ready to be used.