# Room and MVVM ## ROOM ### Room Persistence Library - An architecture component - A database layer on top of SQLite - Takes care of tasks that `SQLiteHelper` dealt with - Like compile-time validation of SQL queries - Allows us to think about objects with fields rather than tables with rows #### Room Components ![image-20220107154928136](img/ad.png) ###### Database - Contains a database holder - A singleton serves as the main access point to persistent data ###### Entities - Java classes that represent (or become) tables in the database ###### DAO - Data Access Object (software design pattern) - An abstract interface for accessing the database to retrieve a given entity #### Database An abstract class that - Is annotated with `@Database` - Extends `RoomDatabase` - Lists the entities associated with the database - Includes abstract methods that return DAO interfaces for the entities Is generally implemented as a **singleton** to retrieve a reference to the database with the application context - Returned by `RoomDatabase.databaseBuilder` A more structured approach to the database lifecycle - `onCreate`, `onOpen`, `onDestructiveMigration` - When the database schema is modified, we must define a migration strategy Room **does not** support database access on the main thread - Queries could take a while, so they shouldn’t be done on the main/UI thread #### Entity - Plain old Java class - Represents a table in the underlying database - Sets of related fields - Annotated to describe how to think about it in terms of the database - Needs to have a `@PrimaryKey` - Field names become column names, unless we annotate an alternate - `@ColumnInfo(name = 'my_column_name')` - `@Ignore` certain fields - Embedded entities, 1-to-1 or 1-to-many relationships - `@Embedded`, `@Relation`, `@Transaction` #### DAOs - Interface / Abstract class - Common practice to have one DAO per entity - Implementation is created at compile time Specify convenience queries, annotated to tell Room what to do - `@Insert` generates an implementation that inserts all parameters into the database in a single transaction. - `@Update` updates a set of entities given as parameters using a query that matches against the primary key of each entity. - If the entity is updated, it will update the underlying SQL database - `@Query` read/write operations as something like a conventional database query. - `@Delete` removes entities given as parameters. ### MVVM Architecture ![image-20220107160502350](img/ae.png) VIEW (UI controller) is the V ViewModel is the current state of the data needed to populate the view Room is the model; it is all the data for the entire application ViewModel $\subset$ (is a subset of) Room Database NOTE: Room is just the database manager, others exist. Repository - as far as the view model is concerned, it asks the repository for all data. It abstracts access to different possible back-ends. The view model doesn’t need to know how the data is stored, e.g. whether data is stored on `data/.cache` or on a web server `ftp://192.168.0.5`. The repository is responsible for connecting to the website and downloading data into cache to support functionality when the internet drops out. **All view models** get their data from the **same repository** # Coding Example ```java import androidx.room.Entity @Entity(tableName = "myTable") public class Record { @PrimaryKey @NonNull @ColumnInfo(name = "name") // only needed if they don't match public Record(@NonNull String name, String colour) { this.name = name; ... } } ``` Interface DAO ```java //Can be an abstract class or interface //Room will generate the implementation based on this import androidx.room.Doa; @Dao public interface RecordDao { @Insert void insert (Record r); @Insert(onConflict = OnConflictStrategy.IGNORE) void insertLots (Record... r); @Query("DELETE FROM myTable") void deleteALl(); @Query("SELECT * FROM myTable ORDER BY name ASC") List getAlphaRecord(); @Query("SELECT * FROM myTable") LiveData> getAlphaRecord(); //LiveData is lifecycle aware } ``` Boilerplate database stuff ```java import androidx.room.RoomDatabase; @Database(entities = {Record.class}, version=1, exportScheme=false) public abstract class myDatabase extends RoomDatabase { public abstract RecordDao(); private static volatile myDatabase INSTANCE; //as we're not allowed to query on the main thread static final ExecutorService dbWriter = Executors.newFixedThreadPool(4); //context needed to know file path static myDatabase getDatabse(final Context context) { if (INSTANCE == null) { synchronised (myDatabase.class) { INSTANCE = Room.databaseBuilder( context.getApplicationContext(), myDatabase.class, "myDatabase") .fallbackToDestructiveMigration() .build(); } } } } ``` Main Activity ```java public class MainActivity extends .. { myDatabase db; RecordDao rDao; protected onCreate (...){ db = myDatabase(getApplicationContext()); rDao = db.recordDao(); } public void addNewRecord(){ myDatabase.dbWriter.execute(() -> { Record r = new Record ("data", "data"); rDao.insert(r); }) } } ```