Files
notes/docs/lectures/mdp/11_room_mvvm.md
T

200 lines
5.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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<Record> getAlphaRecord();
@Query("SELECT * FROM myTable")
LiveData<List<Record>> 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);
})
}
}
```