SlideShare a Scribd company logo
1 of 79
Download to read offline
ANDROID
ARCHITECTURE
COMPONENTS -
INTRODUCTION
Paulina Szklarska
Hello!
Nice to meet you
Paulina Szklarska
Android Developer @ DroidsOnRoids
co-organizer of Toast Wrocław meetups
cat owner
travel enthusiast
@pszklarska
@pszklarska
@p_szklarska
1.
INTRO
What are
Architecture
Components?
November, 6
2017
ARCHITECTURE COMPONENTS
ROOM
LIFECYCLE COMPONENTS VIEW MODEL
LIVE DATA PAGING LIBRARY
ROOM
Persistence library for Android
Room Entity
Single database table
DAO
Defines methods to access database
Database
Holds entities and DAOs
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
Room
Entity,
DAO,
Database
Cats
id
1
2
3
name
Fudge
Houdini
Scratchy
url
/fudge_photo.jpg
/houdini_photo.jpg
/scratchy_photo.jpg
@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
@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
@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
@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
@Dao

public interface CatDao {



@Query("SELECT * FROM kittens")

List<Cat> getAllCats();



@Insert

void insert(Cat... cats);



@Update

void update(Cat... cats);



@Delete

void delete(Cat... cats);

}a
@Dao

public interface CatDao {



@Insert

void insert(Cat... cats);



@Insert

void insert(Cat cat);



@Insert

void insert(List<Cat> catList);



}a
@Dao

public interface CatDao {



@Insert(onConflict = REPLACE)

void insert(Cat... cats);



@Insert(onConflict = IGNORE)

void insert(Cat cat);



@Insert

void insert(List<Cat> catList);



}a
@Dao

public interface CatDao {



@Query("SELECT * FROM kittens")

List<Cat> getAllCats();



@Query("SELECT * FROM kittens WHERE id=:id")

Cat getCatById(int id);



@Query("SELECT * FROM kittens")

Cursor getCatsCursor();



@Query("SELECT * FROM kittens WHERE name=:name LIMIT :max")

List<Cat> getCatsByName(String name, int max);



}a
!UI thread
@Database(entities = { Cat.class }, version = 1)

public abstract class CatDatabase extends RoomDatabase {



private static final String DB_NAME = "catsDatabase.db";



private static CatDatabase create(final Context context) {

return Room

.databaseBuilder(context, CatDatabase.class, DB_NAME)

.build();

}




public abstract CatDao getCatDao();

}a
CatDatabase

.getInstance(context)

.getCatDao()

.insert(new Cat(1, 

"Muffin", 

"/muffin.jpg"));
List<Cat> allCats = CatDatabase

.getInstance(context)

.getCatDao()

.getAllCats();
Cats
id
1
2
3
name
Fudge
Houdini
Scratchy
url
/fudge_photo.jpg
/houdini_photo.jpg
/scratchy_photo.jpg
Owner
id
1
2
3
login
John
Cindy
Ken
avatar_url
„/john.jpg”
„/cindy.jpg”
„/ken.jpg”
ownerId
1
1
2
Room
Relations -
@ForeignKey
@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
@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
@Dao

public interface CatDao {



@Query("SELECT * FROM kittens WHERE ownerId=:ownerId")

List<Cat> findCatsForOwner(int ownerId);



}a

Room
Relations -
@Relation
@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
@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
public class OwnerWithCats {

@Embedded public Owner owner;



@Relation(parentColumn = "id",

entityColumn = "ownerId")
public List<Cat> catList;

}a
@Dao

public interface OwnerWithCatsDao {



@Query("SELECT * FROM owner")

public List<OwnerWithCats> getOwnersWithCats();



}a
Room
Custom Types
@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
public class DateConverter {



@TypeConverter
public LocalDate toDate(long dateLong) {
return LocalDate.ofEpochDay(dateLong);
}
@TypeConverter
public long fromDate(LocalDate date) {
return date.toEpochDay();
}

}
@Database(entities = { Cat.class }, version = 1)

@TypeConverters(DateConverter.class)

public abstract class CatDatabase extends RoomDatabase {



}a
Room
Migrations
@Entity

public class Cat {

@PrimaryKey public int id;

public String name;

public String url;

}a
@Entity

public class Cat {

@PrimaryKey public int id;

public String name;

public String url;

public String age;

}a
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.
@Database(entities = { Cat.class }, version = 1)a

public abstract class CatDatabase extends RoomDatabase {

private static CatDatabase create(final Context context) {

return Room

.databaseBuilder(context, CatDatabase.class, DB_NAME)

.build();
}a
}a
@Database(entities = { Cat.class }, version = 2)a

public abstract class CatDatabase extends RoomDatabase {

private static CatDatabase create(final Context context) {

return Room

.databaseBuilder(context, CatDatabase.class, DB_NAME)

.build();
}a
}a
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.
@Database(entities = { Cat.class }, version = 2)a

public abstract class CatDatabase extends RoomDatabase {

private static CatDatabase create(final Context context) {

return Room

.databaseBuilder(context, CatDatabase.class, DB_NAME)
.fallbackToDestructiveMigration()

.build();

}a

}a
@Database(entities = { Cat.class }, version = 2)a

public abstract class CatDatabase extends RoomDatabase {

private static CatDatabase create(final Context context) {

return Room

.databaseBuilder(context, CatDatabase.class, DB_NAME)

.addMigrations(Migrations.FROM_1_TO_2)

.build();

}a

}a
class Migrations {

static final Migration FROM_1_TO_2 = new Migration(1, 2) {

@Override

public void migrate(@NonNull final SupportSQLiteDatabase database) {

database.execSQL("ALTER TABLE kittens ADD COLUMN age TEXT");

}

};

}
android {
javaCompileOptions {

annotationProcessorOptions {

arguments = ["room.schemaLocation":

"$projectDir/schemas".toString()]

}

}

}
}
app/schemas/pl.pszklarska.kittyarchitecture.data.CatDatabase/1.json
"tableName": „kittens",

"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER NOT NULL, `name` TEXT,
`url` TEXT, PRIMARY KEY(`id`))",

"fields": [

{

"fieldPath": "id",

"columnName": "id",

"affinity": "INTEGER",

"notNull": true

},

{

"fieldPath": "name",

"columnName": "name",

"affinity": "TEXT",

"notNull": false

},
. . .
]
@Database(entities = { Cat.class }, version = 2)a

public abstract class CatDatabase extends RoomDatabase {

private static CatDatabase create(final Context context) {

return Room

.databaseBuilder(context, CatDatabase.class, DB_NAME)

.addMigrations(Migrations.FROM_1_TO_2,

Migrations.FROM_2_TO_3)

.build();

}a

}a
@Database(entities = { Cat.class }, version = 3)a

public abstract class CatDatabase extends RoomDatabase {

private static CatDatabase create(final Context context) {

return Room

.databaseBuilder(context, CatDatabase.class, DB_NAME)

.addMigrations(Migrations.FROM_1_TO_3)

.build();

}a

}a
Room
Testing
@RunWith(AndroidJUnit4.class)

public class CatEntityTest {

private CatDao catDao;

private CatDatabase database;



@Before

public void createDb() {

Context context = InstrumentationRegistry.getTargetContext();

database = Room.inMemoryDatabaseBuilder(context, CatDatabase.class).build();

catDao = database.getCatDao();

}



@Test

public void writeCatAndReadInList() throws Exception {

Cat cat = new Cat(1, "Jake", „fake_url");

catDao.insert(cat);

List<Cat> catsByName = catDao.getCatsByName(„Jake");

assertThat(catsByName.get(0), equalTo(cat));

}
@After

public void closeDb() throws IOException {

database.close();

}

}
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
LIFECYCLE
Lifecycle-aware components
LOLcycle
LIFECYCLE
COMPONENTS
LIFECYCLE
OWNER
LIFECYCLE
OBSERVER
- FragmentActivity
- Fragment (support)
- AppCompatActivity
INITIALIZED RESUMEDSTARTEDCREATED
DESTROYED RESUMEDSTARTEDCREATED
ON_CREATE ON_START ON_RESUME
ON_PAUSEON_STOPON_DESTROY
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();

}



@Override

protected void onStart() {

super.onStart();

locationManager.addLocationListener();

}



@Override

protected void onStop() {

super.onStop();

locationManager.removeLocationListener();

}



@Override

public void onLocationChanged(final Location location) {

Log.d(„MainActivity", „Location changed: " + location.toString());

}

public class LocationManager implements LifecycleObserver {



public LocationManager(LifecycleOwner lifecycleOwner) {
// do something 

lifecycleOwner.getLifecycle().addObserver(this);

}a



@OnLifecycleEvent(Lifecycle.Event.ON_START)

void addLocationListener() {

// register location manager listener

}a



@OnLifecycleEvent(Lifecycle.Event.ON_STOP)

void removeLocationListener() {

// remove location manager listener

}a

}a
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();

}a



@Override

protected void onStart() {

super.onStart();

locationManager.addLocationListener();

}



@Override

protected void onStop() {

super.onStop();

locationManager.removeLocationListener();

}



@Override

public void onLocationChanged(final Location location) {

Log.d(„MainActivity", „Location changed: " + location.toString());

}

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
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
public class GithubApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
ProcessLifecycleOwner.get()
.getLifecycle()
.addObserver(new AppLifecycleObserver());
}
}
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
}
}
ViewModel
ACTIVITY
Rotation
ACTIVITY
RECREATED
UI Data
Holder
UI Data
Holder
?
?
ACTIVITY
ACTIVITY
RECREATED
ViewModel
• don’t worry
about UI
data holder
• data will
wait for us
• data will be
always
updated
even after
activity
recreating
Rotation
public class UsersViewModel extends ViewModel {



private List<User> userList;



public List<User> getUserList() {

if (userList == null) {

usersList = loadUsers();

}

return userList;

}



private List<User> loadUsers() {

// do something to load users

}

}
public class UsersViewModel extends AndroidViewModel {

public UsersViewModel(final Application application) {
super(application);
}


private List<User> userList;



public List<User> getUserList() {

if (userList == null) {

usersList = loadUsers();

}

return userList;

}



private List<User> loadUsers() {

// do something to load users

}

}
public class UsersActivity extends AppCompatActivity {



@Override

protected void onCreate(final Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);



UsersViewModel usersViewModel =

ViewModelProviders.of(this).get(UsersViewModel.class);



showUsers(usersViewModel.getUserList());

}a

}a
LiveData
Lifecycle + Data
LiveData<List<User>> observes
notifies
only if activity is
at least started
List<User>
public class UsersViewModel extends ViewModel {



private MutableLiveData<List<User>> userList =
new MutableLiveData<>();



public List<User> getUserList() {

if (userList == null) {

usersList = loadUsers();

}a

return userList;

}a



private List<User> loadUsers() {

// do something to load users

}a

}a
public class UsersViewModel extends ViewModel {



private MutableLiveData<List<User>> userList =
new MutableLiveData<>();
public UsersViewModel() {

setUserListRefreshCallback(newUserList -> {

userList.postValue(newUserList);

});

}a



public LiveData<List<User>> getUserList() {

return userList;

}a

}a
public class UsersActivity extends AppCompatActivity {



@Override

protected void onCreate(final Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);



UsersViewModel usersViewModel =

ViewModelProviders.of(this).get(UsersViewModel.class);



usersViewModel.getUserList().observe(this, this::showUsers);


}a

}a
tl;dr • keeps your UI always updated (follows
observer pattern)
• no memory leaks (data bound with
lifecycle)
• no data sent to stopped activity
@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

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
Thanks!
Any questions?
Paulina Szklarska
@pszklarska
@pszklarska
@p_szklarska

More Related Content

What's hot

Easy data-with-spring-data-jpa
Easy data-with-spring-data-jpaEasy data-with-spring-data-jpa
Easy data-with-spring-data-jpaStaples
 
Data access 2.0? Please welcome: Spring Data!
Data access 2.0? Please welcome: Spring Data!Data access 2.0? Please welcome: Spring Data!
Data access 2.0? Please welcome: Spring Data!Oliver Gierke
 
บทที่ 4 การเพิ่มข้อมูลลงฐานข้อมูล
บทที่ 4 การเพิ่มข้อมูลลงฐานข้อมูลบทที่ 4 การเพิ่มข้อมูลลงฐานข้อมูล
บทที่ 4 การเพิ่มข้อมูลลงฐานข้อมูลPriew Chakrit
 
Clojure for Java developers
Clojure for Java developersClojure for Java developers
Clojure for Java developersJohn Stevenson
 
JavaEE 8 on a diet with Payara Micro 5
JavaEE 8 on a diet with Payara Micro 5JavaEE 8 on a diet with Payara Micro 5
JavaEE 8 on a diet with Payara Micro 5Payara
 
Alternatives of JPA/Hibernate
Alternatives of JPA/HibernateAlternatives of JPA/Hibernate
Alternatives of JPA/HibernateSunghyouk Bae
 
2001: JNDI Its all in the Context
2001:  JNDI Its all in the Context2001:  JNDI Its all in the Context
2001: JNDI Its all in the ContextRussell Castagnaro
 
JQuery New Evolution
JQuery New EvolutionJQuery New Evolution
JQuery New EvolutionAllan Huang
 
No sql databases blrdroid devfest 2016
No sql databases   blrdroid devfest 2016No sql databases   blrdroid devfest 2016
No sql databases blrdroid devfest 2016amsanjeev
 
Jpa queries
Jpa queriesJpa queries
Jpa queriesgedoplan
 
09.Local Database Files and Storage on WP
09.Local Database Files and Storage on WP09.Local Database Files and Storage on WP
09.Local Database Files and Storage on WPNguyen Tuan
 

What's hot (18)

Easy data-with-spring-data-jpa
Easy data-with-spring-data-jpaEasy data-with-spring-data-jpa
Easy data-with-spring-data-jpa
 
Data access 2.0? Please welcome: Spring Data!
Data access 2.0? Please welcome: Spring Data!Data access 2.0? Please welcome: Spring Data!
Data access 2.0? Please welcome: Spring Data!
 
บทที่ 4 การเพิ่มข้อมูลลงฐานข้อมูล
บทที่ 4 การเพิ่มข้อมูลลงฐานข้อมูลบทที่ 4 การเพิ่มข้อมูลลงฐานข้อมูล
บทที่ 4 การเพิ่มข้อมูลลงฐานข้อมูล
 
Insert
InsertInsert
Insert
 
Clojure for Java developers
Clojure for Java developersClojure for Java developers
Clojure for Java developers
 
Into Clojure
Into ClojureInto Clojure
Into Clojure
 
JavaEE 8 on a diet with Payara Micro 5
JavaEE 8 on a diet with Payara Micro 5JavaEE 8 on a diet with Payara Micro 5
JavaEE 8 on a diet with Payara Micro 5
 
Alternatives of JPA/Hibernate
Alternatives of JPA/HibernateAlternatives of JPA/Hibernate
Alternatives of JPA/Hibernate
 
Spock
SpockSpock
Spock
 
2001: JNDI Its all in the Context
2001:  JNDI Its all in the Context2001:  JNDI Its all in the Context
2001: JNDI Its all in the Context
 
XTW_Import
XTW_ImportXTW_Import
XTW_Import
 
Spring data requery
Spring data requerySpring data requery
Spring data requery
 
JQuery New Evolution
JQuery New EvolutionJQuery New Evolution
JQuery New Evolution
 
No sql databases blrdroid devfest 2016
No sql databases   blrdroid devfest 2016No sql databases   blrdroid devfest 2016
No sql databases blrdroid devfest 2016
 
Jpa queries
Jpa queriesJpa queries
Jpa queries
 
Spring Data JPA
Spring Data JPASpring Data JPA
Spring Data JPA
 
4 gouping object
4 gouping object4 gouping object
4 gouping object
 
09.Local Database Files and Storage on WP
09.Local Database Files and Storage on WP09.Local Database Files and Storage on WP
09.Local Database Files and Storage on WP
 

Similar to Android Architecture Components - Introduction

NoSQL Endgame Percona Live Online 2020
NoSQL Endgame Percona Live Online 2020NoSQL Endgame Percona Live Online 2020
NoSQL Endgame Percona Live Online 2020Thodoris Bais
 
Annotation processing and code gen
Annotation processing and code genAnnotation processing and code gen
Annotation processing and code genkoji lin
 
Android Architecture Components - Guy Bar on, Vonage
Android Architecture Components - Guy Bar on, VonageAndroid Architecture Components - Guy Bar on, Vonage
Android Architecture Components - Guy Bar on, VonageDroidConTLV
 
Lombokの紹介
Lombokの紹介Lombokの紹介
Lombokの紹介onozaty
 
NOSQL part of the SpringOne 2GX 2010 keynote
NOSQL part of the SpringOne 2GX 2010 keynoteNOSQL part of the SpringOne 2GX 2010 keynote
NOSQL part of the SpringOne 2GX 2010 keynoteEmil Eifrem
 
Android Architecture - Khoa Tran
Android Architecture -  Khoa TranAndroid Architecture -  Khoa Tran
Android Architecture - Khoa TranTu Le Dinh
 
Entity Framework Core & Micro-Orms with Asp.Net Core
Entity Framework Core & Micro-Orms with Asp.Net CoreEntity Framework Core & Micro-Orms with Asp.Net Core
Entity Framework Core & Micro-Orms with Asp.Net CoreStephane Belkheraz
 
Тарас Олексин - Sculpt! Your! Tests!
Тарас Олексин  - Sculpt! Your! Tests!Тарас Олексин  - Sculpt! Your! Tests!
Тарас Олексин - Sculpt! Your! Tests!DataArt
 
NoSQL Endgame - Java2Days 2020 Virtual
NoSQL Endgame - Java2Days 2020 VirtualNoSQL Endgame - Java2Days 2020 Virtual
NoSQL Endgame - Java2Days 2020 VirtualWerner Keil
 
Architecture components - IT Talk
Architecture components - IT TalkArchitecture components - IT Talk
Architecture components - IT TalkConstantine Mars
 
Architecture Components
Architecture Components Architecture Components
Architecture Components DataArt
 
Android dev toolbox
Android dev toolboxAndroid dev toolbox
Android dev toolboxShem Magnezi
 
JakartaData-JCon.pptx
JakartaData-JCon.pptxJakartaData-JCon.pptx
JakartaData-JCon.pptxEmilyJiang23
 
Spring data ii
Spring data iiSpring data ii
Spring data ii명철 강
 
MobiConf 2018 | Room: an SQLite object mapping library
MobiConf 2018 | Room: an SQLite object mapping library MobiConf 2018 | Room: an SQLite object mapping library
MobiConf 2018 | Room: an SQLite object mapping library Magda Miu
 
比XML更好用的Java Annotation
比XML更好用的Java Annotation比XML更好用的Java Annotation
比XML更好用的Java Annotationjavatwo2011
 
EclipseCon2011 Cross-Platform Mobile Development with Eclipse
EclipseCon2011 Cross-Platform Mobile Development with EclipseEclipseCon2011 Cross-Platform Mobile Development with Eclipse
EclipseCon2011 Cross-Platform Mobile Development with EclipseHeiko Behrens
 

Similar to Android Architecture Components - Introduction (20)

Architecure components by Paulina Szklarska
Architecure components by Paulina SzklarskaArchitecure components by Paulina Szklarska
Architecure components by Paulina Szklarska
 
NoSQL Endgame Percona Live Online 2020
NoSQL Endgame Percona Live Online 2020NoSQL Endgame Percona Live Online 2020
NoSQL Endgame Percona Live Online 2020
 
Requery overview
Requery overviewRequery overview
Requery overview
 
Annotation processing and code gen
Annotation processing and code genAnnotation processing and code gen
Annotation processing and code gen
 
Android Architecture Components - Guy Bar on, Vonage
Android Architecture Components - Guy Bar on, VonageAndroid Architecture Components - Guy Bar on, Vonage
Android Architecture Components - Guy Bar on, Vonage
 
Lombokの紹介
Lombokの紹介Lombokの紹介
Lombokの紹介
 
NOSQL part of the SpringOne 2GX 2010 keynote
NOSQL part of the SpringOne 2GX 2010 keynoteNOSQL part of the SpringOne 2GX 2010 keynote
NOSQL part of the SpringOne 2GX 2010 keynote
 
Android Architecture - Khoa Tran
Android Architecture -  Khoa TranAndroid Architecture -  Khoa Tran
Android Architecture - Khoa Tran
 
Entity Framework Core & Micro-Orms with Asp.Net Core
Entity Framework Core & Micro-Orms with Asp.Net CoreEntity Framework Core & Micro-Orms with Asp.Net Core
Entity Framework Core & Micro-Orms with Asp.Net Core
 
Тарас Олексин - Sculpt! Your! Tests!
Тарас Олексин  - Sculpt! Your! Tests!Тарас Олексин  - Sculpt! Your! Tests!
Тарас Олексин - Sculpt! Your! Tests!
 
NoSQL Endgame - Java2Days 2020 Virtual
NoSQL Endgame - Java2Days 2020 VirtualNoSQL Endgame - Java2Days 2020 Virtual
NoSQL Endgame - Java2Days 2020 Virtual
 
Architecture components - IT Talk
Architecture components - IT TalkArchitecture components - IT Talk
Architecture components - IT Talk
 
Architecture Components
Architecture Components Architecture Components
Architecture Components
 
Android dev toolbox
Android dev toolboxAndroid dev toolbox
Android dev toolbox
 
JakartaData-JCon.pptx
JakartaData-JCon.pptxJakartaData-JCon.pptx
JakartaData-JCon.pptx
 
Spring data ii
Spring data iiSpring data ii
Spring data ii
 
MobiConf 2018 | Room: an SQLite object mapping library
MobiConf 2018 | Room: an SQLite object mapping library MobiConf 2018 | Room: an SQLite object mapping library
MobiConf 2018 | Room: an SQLite object mapping library
 
比XML更好用的Java Annotation
比XML更好用的Java Annotation比XML更好用的Java Annotation
比XML更好用的Java Annotation
 
Spring data
Spring dataSpring data
Spring data
 
EclipseCon2011 Cross-Platform Mobile Development with Eclipse
EclipseCon2011 Cross-Platform Mobile Development with EclipseEclipseCon2011 Cross-Platform Mobile Development with Eclipse
EclipseCon2011 Cross-Platform Mobile Development with Eclipse
 

Recently uploaded

Unlocking the Potential of the Cloud for IBM Power Systems
Unlocking the Potential of the Cloud for IBM Power SystemsUnlocking the Potential of the Cloud for IBM Power Systems
Unlocking the Potential of the Cloud for IBM Power SystemsPrecisely
 
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...shyamraj55
 
Key Features Of Token Development (1).pptx
Key  Features Of Token  Development (1).pptxKey  Features Of Token  Development (1).pptx
Key Features Of Token Development (1).pptxLBM Solutions
 
AI as an Interface for Commercial Buildings
AI as an Interface for Commercial BuildingsAI as an Interface for Commercial Buildings
AI as an Interface for Commercial BuildingsMemoori
 
Benefits Of Flutter Compared To Other Frameworks
Benefits Of Flutter Compared To Other FrameworksBenefits Of Flutter Compared To Other Frameworks
Benefits Of Flutter Compared To Other FrameworksSoftradix Technologies
 
Enhancing Worker Digital Experience: A Hands-on Workshop for Partners
Enhancing Worker Digital Experience: A Hands-on Workshop for PartnersEnhancing Worker Digital Experience: A Hands-on Workshop for Partners
Enhancing Worker Digital Experience: A Hands-on Workshop for PartnersThousandEyes
 
Pigging Solutions in Pet Food Manufacturing
Pigging Solutions in Pet Food ManufacturingPigging Solutions in Pet Food Manufacturing
Pigging Solutions in Pet Food ManufacturingPigging Solutions
 
APIForce Zurich 5 April Automation LPDG
APIForce Zurich 5 April  Automation LPDGAPIForce Zurich 5 April  Automation LPDG
APIForce Zurich 5 April Automation LPDGMarianaLemus7
 
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks..."LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...Fwdays
 
Understanding the Laravel MVC Architecture
Understanding the Laravel MVC ArchitectureUnderstanding the Laravel MVC Architecture
Understanding the Laravel MVC ArchitecturePixlogix Infotech
 
Human Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR SystemsHuman Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR SystemsMark Billinghurst
 
Designing IA for AI - Information Architecture Conference 2024
Designing IA for AI - Information Architecture Conference 2024Designing IA for AI - Information Architecture Conference 2024
Designing IA for AI - Information Architecture Conference 2024Enterprise Knowledge
 
My Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 PresentationMy Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 PresentationRidwan Fadjar
 
Scanning the Internet for External Cloud Exposures via SSL Certs
Scanning the Internet for External Cloud Exposures via SSL CertsScanning the Internet for External Cloud Exposures via SSL Certs
Scanning the Internet for External Cloud Exposures via SSL CertsRizwan Syed
 
Artificial intelligence in the post-deep learning era
Artificial intelligence in the post-deep learning eraArtificial intelligence in the post-deep learning era
Artificial intelligence in the post-deep learning eraDeakin University
 
Transcript: #StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
Transcript: #StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024Transcript: #StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
Transcript: #StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024BookNet Canada
 
Build your next Gen AI Breakthrough - April 2024
Build your next Gen AI Breakthrough - April 2024Build your next Gen AI Breakthrough - April 2024
Build your next Gen AI Breakthrough - April 2024Neo4j
 

Recently uploaded (20)

Unlocking the Potential of the Cloud for IBM Power Systems
Unlocking the Potential of the Cloud for IBM Power SystemsUnlocking the Potential of the Cloud for IBM Power Systems
Unlocking the Potential of the Cloud for IBM Power Systems
 
The transition to renewables in India.pdf
The transition to renewables in India.pdfThe transition to renewables in India.pdf
The transition to renewables in India.pdf
 
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
 
Key Features Of Token Development (1).pptx
Key  Features Of Token  Development (1).pptxKey  Features Of Token  Development (1).pptx
Key Features Of Token Development (1).pptx
 
AI as an Interface for Commercial Buildings
AI as an Interface for Commercial BuildingsAI as an Interface for Commercial Buildings
AI as an Interface for Commercial Buildings
 
Benefits Of Flutter Compared To Other Frameworks
Benefits Of Flutter Compared To Other FrameworksBenefits Of Flutter Compared To Other Frameworks
Benefits Of Flutter Compared To Other Frameworks
 
Enhancing Worker Digital Experience: A Hands-on Workshop for Partners
Enhancing Worker Digital Experience: A Hands-on Workshop for PartnersEnhancing Worker Digital Experience: A Hands-on Workshop for Partners
Enhancing Worker Digital Experience: A Hands-on Workshop for Partners
 
Pigging Solutions in Pet Food Manufacturing
Pigging Solutions in Pet Food ManufacturingPigging Solutions in Pet Food Manufacturing
Pigging Solutions in Pet Food Manufacturing
 
APIForce Zurich 5 April Automation LPDG
APIForce Zurich 5 April  Automation LPDGAPIForce Zurich 5 April  Automation LPDG
APIForce Zurich 5 April Automation LPDG
 
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks..."LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
 
Understanding the Laravel MVC Architecture
Understanding the Laravel MVC ArchitectureUnderstanding the Laravel MVC Architecture
Understanding the Laravel MVC Architecture
 
Human Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR SystemsHuman Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR Systems
 
Designing IA for AI - Information Architecture Conference 2024
Designing IA for AI - Information Architecture Conference 2024Designing IA for AI - Information Architecture Conference 2024
Designing IA for AI - Information Architecture Conference 2024
 
Hot Sexy call girls in Panjabi Bagh 🔝 9953056974 🔝 Delhi escort Service
Hot Sexy call girls in Panjabi Bagh 🔝 9953056974 🔝 Delhi escort ServiceHot Sexy call girls in Panjabi Bagh 🔝 9953056974 🔝 Delhi escort Service
Hot Sexy call girls in Panjabi Bagh 🔝 9953056974 🔝 Delhi escort Service
 
E-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptx
E-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptxE-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptx
E-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptx
 
My Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 PresentationMy Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 Presentation
 
Scanning the Internet for External Cloud Exposures via SSL Certs
Scanning the Internet for External Cloud Exposures via SSL CertsScanning the Internet for External Cloud Exposures via SSL Certs
Scanning the Internet for External Cloud Exposures via SSL Certs
 
Artificial intelligence in the post-deep learning era
Artificial intelligence in the post-deep learning eraArtificial intelligence in the post-deep learning era
Artificial intelligence in the post-deep learning era
 
Transcript: #StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
Transcript: #StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024Transcript: #StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
Transcript: #StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
 
Build your next Gen AI Breakthrough - April 2024
Build your next Gen AI Breakthrough - April 2024Build your next Gen AI Breakthrough - April 2024
Build your next Gen AI Breakthrough - April 2024
 

Android Architecture Components - Introduction

  • 2. Hello! Nice to meet you Paulina Szklarska Android Developer @ DroidsOnRoids co-organizer of Toast Wrocław meetups cat owner travel enthusiast @pszklarska @pszklarska @p_szklarska
  • 4.
  • 6. ARCHITECTURE COMPONENTS ROOM LIFECYCLE COMPONENTS VIEW MODEL LIVE DATA PAGING LIBRARY
  • 8. Room Entity Single database table DAO Defines methods to access database Database Holds entities and DAOs
  • 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
  • 16. @Dao
 public interface CatDao {
 
 @Query("SELECT * FROM kittens")
 List<Cat> getAllCats();
 
 @Insert
 void insert(Cat... cats);
 
 @Update
 void update(Cat... cats);
 
 @Delete
 void delete(Cat... cats);
 }a
  • 17. @Dao
 public interface CatDao {
 
 @Insert
 void insert(Cat... cats);
 
 @Insert
 void insert(Cat cat);
 
 @Insert
 void insert(List<Cat> catList);
 
 }a
  • 18. @Dao
 public interface CatDao {
 
 @Insert(onConflict = REPLACE)
 void insert(Cat... cats);
 
 @Insert(onConflict = IGNORE)
 void insert(Cat cat);
 
 @Insert
 void insert(List<Cat> catList);
 
 }a
  • 19. @Dao
 public interface CatDao {
 
 @Query("SELECT * FROM kittens")
 List<Cat> getAllCats();
 
 @Query("SELECT * FROM kittens WHERE id=:id")
 Cat getCatById(int id);
 
 @Query("SELECT * FROM kittens")
 Cursor getCatsCursor();
 
 @Query("SELECT * FROM kittens WHERE name=:name LIMIT :max")
 List<Cat> getCatsByName(String name, int max);
 
 }a !UI thread
  • 20. @Database(entities = { Cat.class }, version = 1)
 public abstract class CatDatabase extends RoomDatabase {
 
 private static final String DB_NAME = "catsDatabase.db";
 
 private static CatDatabase create(final Context context) {
 return Room
 .databaseBuilder(context, CatDatabase.class, DB_NAME)
 .build();
 } 
 
 public abstract CatDao getCatDao();
 }a
  • 21. CatDatabase
 .getInstance(context)
 .getCatDao()
 .insert(new Cat(1, 
 "Muffin", 
 "/muffin.jpg")); List<Cat> allCats = CatDatabase
 .getInstance(context)
 .getCatDao()
 .getAllCats();
  • 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
  • 31. @Dao
 public interface OwnerWithCatsDao {
 
 @Query("SELECT * FROM owner")
 public List<OwnerWithCats> getOwnersWithCats();
 
 }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
  • 37. @Entity
 public class Cat {
 @PrimaryKey public int id;
 public String name;
 public String url;
 }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.
  • 40. @Database(entities = { Cat.class }, version = 1)a
 public abstract class CatDatabase extends RoomDatabase {
 private static CatDatabase create(final Context context) {
 return Room
 .databaseBuilder(context, CatDatabase.class, DB_NAME)
 .build(); }a }a
  • 41. @Database(entities = { Cat.class }, version = 2)a
 public abstract class CatDatabase extends RoomDatabase {
 private static CatDatabase create(final Context context) {
 return Room
 .databaseBuilder(context, CatDatabase.class, DB_NAME)
 .build(); }a }a
  • 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.
  • 43. @Database(entities = { Cat.class }, version = 2)a
 public abstract class CatDatabase extends RoomDatabase {
 private static CatDatabase create(final Context context) {
 return Room
 .databaseBuilder(context, CatDatabase.class, DB_NAME) .fallbackToDestructiveMigration()
 .build();
 }a
 }a
  • 44. @Database(entities = { Cat.class }, version = 2)a
 public abstract class CatDatabase extends RoomDatabase {
 private static CatDatabase create(final Context context) {
 return Room
 .databaseBuilder(context, CatDatabase.class, DB_NAME)
 .addMigrations(Migrations.FROM_1_TO_2)
 .build();
 }a
 }a
  • 45. class Migrations {
 static final Migration FROM_1_TO_2 = new Migration(1, 2) {
 @Override
 public void migrate(@NonNull final SupportSQLiteDatabase database) {
 database.execSQL("ALTER TABLE kittens ADD COLUMN age TEXT");
 }
 };
 }
  • 46. android { javaCompileOptions {
 annotationProcessorOptions {
 arguments = ["room.schemaLocation":
 "$projectDir/schemas".toString()]
 }
 }
 } }
  • 47. app/schemas/pl.pszklarska.kittyarchitecture.data.CatDatabase/1.json "tableName": „kittens",
 "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER NOT NULL, `name` TEXT, `url` TEXT, PRIMARY KEY(`id`))",
 "fields": [
 {
 "fieldPath": "id",
 "columnName": "id",
 "affinity": "INTEGER",
 "notNull": true
 },
 {
 "fieldPath": "name",
 "columnName": "name",
 "affinity": "TEXT",
 "notNull": false
 }, . . . ]
  • 48. @Database(entities = { Cat.class }, version = 2)a
 public abstract class CatDatabase extends RoomDatabase {
 private static CatDatabase create(final Context context) {
 return Room
 .databaseBuilder(context, CatDatabase.class, DB_NAME)
 .addMigrations(Migrations.FROM_1_TO_2,
 Migrations.FROM_2_TO_3)
 .build();
 }a
 }a
  • 49. @Database(entities = { Cat.class }, version = 3)a
 public abstract class CatDatabase extends RoomDatabase {
 private static CatDatabase create(final Context context) {
 return Room
 .databaseBuilder(context, CatDatabase.class, DB_NAME)
 .addMigrations(Migrations.FROM_1_TO_3)
 .build();
 }a
 }a
  • 51. @RunWith(AndroidJUnit4.class)
 public class CatEntityTest {
 private CatDao catDao;
 private CatDatabase database;
 
 @Before
 public void createDb() {
 Context context = InstrumentationRegistry.getTargetContext();
 database = Room.inMemoryDatabaseBuilder(context, CatDatabase.class).build();
 catDao = database.getCatDao();
 }
 
 @Test
 public void writeCatAndReadInList() throws Exception {
 Cat cat = new Cat(1, "Jake", „fake_url");
 catDao.insert(cat);
 List<Cat> catsByName = catDao.getCatsByName(„Jake");
 assertThat(catsByName.get(0), equalTo(cat));
 } @After
 public void closeDb() throws IOException {
 database.close();
 }
 }
  • 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
  • 57. 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();
 }
 
 @Override
 protected void onStart() {
 super.onStart();
 locationManager.addLocationListener();
 }
 
 @Override
 protected void onStop() {
 super.onStop();
 locationManager.removeLocationListener();
 }
 
 @Override
 public void onLocationChanged(final Location location) {
 Log.d(„MainActivity", „Location changed: " + location.toString());
 }

  • 58. public class LocationManager implements LifecycleObserver {
 
 public LocationManager(LifecycleOwner lifecycleOwner) { // do something 
 lifecycleOwner.getLifecycle().addObserver(this);
 }a
 
 @OnLifecycleEvent(Lifecycle.Event.ON_START)
 void addLocationListener() {
 // register location manager listener
 }a
 
 @OnLifecycleEvent(Lifecycle.Event.ON_STOP)
 void removeLocationListener() {
 // remove location manager listener
 }a
 }a
  • 59. 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();
 }a
 
 @Override
 protected void onStart() {
 super.onStart();
 locationManager.addLocationListener();
 }
 
 @Override
 protected void onStop() {
 super.onStop();
 locationManager.removeLocationListener();
 }
 
 @Override
 public void onLocationChanged(final Location location) {
 Log.d(„MainActivity", „Location changed: " + location.toString());
 }

  • 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 } }
  • 66. ACTIVITY ACTIVITY RECREATED ViewModel • don’t worry about UI data holder • data will wait for us • data will be always updated even after activity recreating Rotation
  • 67. public class UsersViewModel extends ViewModel {
 
 private List<User> userList;
 
 public List<User> getUserList() {
 if (userList == null) {
 usersList = loadUsers();
 }
 return userList;
 }
 
 private List<User> loadUsers() {
 // do something to load users
 }
 }
  • 68. public class UsersViewModel extends AndroidViewModel {
 public UsersViewModel(final Application application) { super(application); } 
 private List<User> userList;
 
 public List<User> getUserList() {
 if (userList == null) {
 usersList = loadUsers();
 }
 return userList;
 }
 
 private List<User> loadUsers() {
 // do something to load users
 }
 }
  • 69. public class UsersActivity extends AppCompatActivity {
 
 @Override
 protected void onCreate(final Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 setContentView(R.layout.activity_main);
 
 UsersViewModel usersViewModel =
 ViewModelProviders.of(this).get(UsersViewModel.class);
 
 showUsers(usersViewModel.getUserList());
 }a
 }a
  • 72. LiveData<List<User>> observes notifies only if activity is at least started List<User>
  • 73. public class UsersViewModel extends ViewModel {
 
 private MutableLiveData<List<User>> userList = new MutableLiveData<>();
 
 public List<User> getUserList() {
 if (userList == null) {
 usersList = loadUsers();
 }a
 return userList;
 }a
 
 private List<User> loadUsers() {
 // do something to load users
 }a
 }a
  • 74. public class UsersViewModel extends ViewModel {
 
 private MutableLiveData<List<User>> userList = new MutableLiveData<>(); public UsersViewModel() {
 setUserListRefreshCallback(newUserList -> {
 userList.postValue(newUserList);
 });
 }a
 
 public LiveData<List<User>> getUserList() {
 return userList;
 }a
 }a
  • 75. public class UsersActivity extends AppCompatActivity {
 
 @Override
 protected void onCreate(final Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 setContentView(R.layout.activity_main);
 
 UsersViewModel usersViewModel =
 ViewModelProviders.of(this).get(UsersViewModel.class);
 
 usersViewModel.getUserList().observe(this, this::showUsers); 
 }a
 }a
  • 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