This document introduces Android Architecture Components and provides an overview of some key components:
- Room is a persistence library that provides an abstraction layer over SQLite to allow for more robust database access while reducing boilerplate code.
- Lifecycle-aware components allow classes to observe Activity and Fragment lifecycles so their behavior is linked to the lifecycle status of other components.
- Additional components like ViewModel, LiveData, and Paging Library are mentioned but not described in detail.
The document focuses on Room by explaining entity, DAO and database classes as well as more advanced Room features like relationships, custom types, migrations and testing. Lifecycle components are introduced to link observer behavior to owner lifec
9. Why
another
database
library?
• less boilerplate code (thanks to annotations)
• SQL statement compile-time validation (less
crashes)
• full compatibility with other Architecture
Components (LiveData) and RxJava
• easy to use
• easy to test
• easy to migrate
12. @Entity
public class Cat {
@PrimaryKey
public int id;
public String name;
public String url;
public Cat(int id, String name, String url) {
this.id = id;
this.name = name;
this.url = url;
}a
}a
13. @Entity(tableName = „kittens”)
public class Cat {
@PrimaryKey
public int id;
public String name;
public String url;
public Cat(int id, String name, String url) {
this.id = id;
this.name = name;
this.url = url;
}a
}a
14. @Entity(tableName = „kittens”)
public class Cat {
@PrimaryKey(autoGenerate = true)
public int id;
public String name;
public String url;
public Cat(String name, String url) {
this.name = name;
this.url = url;
}a
}a
15. @Entity(tableName = „kittens”)
public class Cat {
@PrimaryKey(autoGenerate = true)
public int id;
public String name;
@ColumnInfo(name = „photo_url”)
public String url;
public Cat(String name, String url) {
this.name = name;
this.url = url;
}a
}a
24. @Entity
public class Owner {
@PrimaryKey
public int id;
public String login;
public String avatarUrl;
public Owner(int id, String login, String avatarUrl) {
this.id = id;
this.login = login;
this.avatarUrl = avatarUrl;
}a
}a
25. @Entity(foreignKeys = @ForeignKey(entity = Owner.class,
parentColumns = "id",
childColumns = "ownerId",
onDelete = CASCADE))
public class Cat {
@PrimaryKey
public int id;
public String name;
public String url;
public int ownerId;
public Cat(int id, String name, String url, int ownerId) {
this.id = id;
this.name = name;
this.url = url;
this.ownerId = ownerId;
}a
}a
26. @Dao
public interface CatDao {
@Query("SELECT * FROM kittens WHERE ownerId=:ownerId")
List<Cat> findCatsForOwner(int ownerId);
}a
28. @Entity
public class Owner {
@PrimaryKey
public int id;
public String login;
public String avatarUrl;
public Owner(int id, String login, String avatarUrl) {
this.id = id;
this.login = login;
this.avatarUrl = avatarUrl;
}a
}a
29. @Entity
public class Cat {
@PrimaryKey
public int id;
public String name;
public String url;
public int ownerId;
public Cat(int id, String name, String url, int ownerId) {
this.id = id;
this.name = name;
this.url = url;
this.ownerId = ownerId;
}a
}a
30. public class OwnerWithCats {
@Embedded public Owner owner;
@Relation(parentColumn = "id",
entityColumn = "ownerId")
public List<Cat> catList;
}a
33. @Entity
public class Cat {
@PrimaryKey
public int id;
public String name;
public LocalDate birthday;
public Cat(int id, String name, LocalDate birthday) {
this.id = id;
this.name = name;
this.birthday = birthday;
}a
}a
34. public class DateConverter {
@TypeConverter
public LocalDate toDate(long dateLong) {
return LocalDate.ofEpochDay(dateLong);
}
@TypeConverter
public long fromDate(LocalDate date) {
return date.toEpochDay();
}
}
35. @Database(entities = { Cat.class }, version = 1)
@TypeConverters(DateConverter.class)
public abstract class CatDatabase extends RoomDatabase {
}a
38. @Entity
public class Cat {
@PrimaryKey public int id;
public String name;
public String url;
public String age;
}a
39. java.lang.IllegalStateException: Room cannot verify the data
integrity. Looks like you've changed schema but forgot to
update the version number. You can simply fix this by
increasing the version number.
42. java.lang.IllegalStateException: A migration from 1 to 2 is necessary.
Please provide a Migration in the builder or call
fallbackToDestructiveMigration in the builder in which case Room will
re-create all of the tables.
52. tl;dw • less boilerplate code
• SQL statement compile-time validation
• full compatibility with other Architecture
Components and RxJava
• easy to use
• easy to test
• easy to migrate
60. public class MainActivity extends AppCompatActivity implements LocationListener {
private LocationManager locationManager;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
locationManager = new LocationManager(this);
}a
@Override
public void onLocationChanged(final Location location) {
Log.d(„MainActivity", „Location changed: " + location.toString());
}a
}a
61. Lifecycle
Observer
It’s the LocationManager which cares
about the Lifecycle. So it should be able
to do it without the activity
babysitting itself.
I’m sure if you look at your code today,
your onStart(), onStop() methods are
like, at least 20, 30 lines of code. We
want them to be zero lines of code.
~Yigit Boyar, Software Enginner, Google,
Google I/O ‚17
62. public class GithubApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
ProcessLifecycleOwner.get()
.getLifecycle()
.addObserver(new AppLifecycleObserver());
}
}
63. public class AppLifecycleObserver implements LifecycleObserver {
@OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
void onFirstActivityCreated() {
// app is in the foreground now
}
@OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
void onLastActivityPaused() {
// app is in the background now
}
}
76. tl;dr • keeps your UI always updated (follows
observer pattern)
• no memory leaks (data bound with
lifecycle)
• no data sent to stopped activity
77. @Dao
public interface CatDao {
@Query("SELECT * FROM cats WHERE name=:name")
LiveData<List<Cat>> getCatsByName(String name);
@Query("SELECT * FROM cats WHERE name=:name")
Flowable<List<Cat>> getCatsByName(String name);
}a
78. Resources Android Architecture Documentation:
https://developer.android.com/topic/libraries/
architecture/index.html
Guide To App Architecture:
https://developer.android.com/topic/libraries/
architecture/guide.html
Google Samples Repository:
https://github.com/googlesamples/android-
architecture-components
Medium series about Architecture Components:
https://medium.com/@pszklarska