5.5 KiB
Room and MVVM
ROOM
Room Persistence Library
- An architecture component
- A database layer on top of SQLite
- Takes care of tasks that
SQLiteHelperdealt with- Like compile-time validation of SQL queries
- Allows us to think about objects with fields rather than tables with rows
- Takes care of tasks that
Room Components
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')
@Ignorecertain fields
- Needs to have a
- 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
@Insertgenerates an implementation that inserts all parameters into the database in a single transaction.@Updateupdates 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
@Queryread/write operations as something like a conventional database query.@Deleteremoves entities given as parameters.
MVVM Architecture
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
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
//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
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
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);
})
}
}

