Extended
Seoul
Architecture Components


alpaca@vcnc.co.kr
Speaker
• (@plazgun)

• Between Android Developer
Architecture Components
• Google I/O 2017 

Architecture Components - Introduction

Architecture Components - Solving the Lifecycle

Architecture Components - Persistence and Offline

• 

• https://developer.android.com/topic/libraries/architecture/
index.html
Architecture Components
• Handling Lifecycles

• LiveData

• ViewModel

• Room
build.gradle
• allprojects {

repositories {

jcenter()

maven { url 'https://maven.google.com' }

}

} 

• compile "android.arch.lifecycle:runtime:1.0.0-alpha3"

compile "android.arch.lifecycle:extensions:1.0.0-alpha3"

annotationProcessor "android.arch.lifecycle:compiler:1.0.0-alpha3"

• compile "android.arch.persistence.room:runtime:1.0.0-alpha3"

annotationProcessor "android.arch.persistence.room:compiler:1.0.0-alpha3"

• compile "android.arch.persistence.room:rxjava2:1.0.0-alpha3"

testCompile "android.arch.persistence.room:testing:1.0.0-alpha3"
Handling Lifecycles
public class MyActivity extends AppCompatActivity {
private TestListener testListener;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
testListener = new TestListener();
}
@Override
protected void onStart() {
super.onStart();
testListener.start();
}
@Override
protected void onStop() {
super.onStop();
testListener.stop();
}
}
public class MyActivity extends AppCompatActivity {
private TestListener testListener;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
testListener = new TestListener();
}
@Override
protected void onStart() {
super.onStart();
testListener.start();
}
@Override
protected void onStop() {
super.onStop();
testListener.stop();
}
}
onStart 

Override .
Lifecycle .
Handling Lifecycles
• Lifecycle

• LifecycleOwner

• LifecycleObserver
public class MyActivity extends LifecycleActivity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_lifecycle);
TestListener testListener = new TestListener(

getLifecycle(), 

result -> {
// update UI
});
}
}
public class TestListener implements LifecycleObserver {
private Lifecycle lifecycle;
public TestListener(Lifecycle lifecycle, TestCallback callback) {
lifecycle.addObserver(this);
this.lifecycle = lifecycle;
}
@OnLifecycleEvent(Lifecycle.Event.ON_START)
void start() {
// start Event
}
@OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
void clean() {
lifecycle.removeObserver(this);
}
}
public class MyActivity extends CustomActivity {
@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

}
}
public class LifecycleActivity extends FragmentActivity 

implements LifecycleRegistryOwner {
private final LifecycleRegistry mRegistry 

= new LifecycleRegistry(this);
@Override
public LifecycleRegistry getLifecycle() {
return mRegistry;
}
}
public class MyActivity extends CustomActivity implements LifecycleRegistryOwner {
private final LifecycleRegistry lifecycleRegistry = new LifecycleRegistry(this);
@Override
public LifecycleRegistry getLifecycle() {
return lifecycleRegistry;
}
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_lifecycle);
TestListener testListener = new TestListener(getLifecycle(), state -> {
// update Ui
});
}
}
public class MyActivity extends LifecycleActivity {
private TestListener testListener;
@Override
protected void onStart() {
super.onStart();
Utils.checkUserStatus(state -> {
if (state.equals("OK")) {
testListener.start();
}
});
}
public class MyActivity extends LifecycleActivity {
private TestListener testListener;
@Override
protected void onStart() {
super.onStart();
// ?
Utils.checkUserStatus(state -> {
if (state.equals("OK")) {
testListener.start();
}
});
}
StartCreate Resume Pause Stop Destroy
testListener.stop
Utils.checkStatus testListener.start
Activity .
public class MyActivity extends LifecycleActivity {
private TestListener testListener;
@Override
protected void onStart() {
super.onStart();
Utils.checkUserStatus(state -> {
if (state.equals("OK") && getLifecycle()

.getCurrentState()

.isAtLeast(Lifecycle.State.STARTED)) {
testListener.start();
}
});
}
LiveData
LiveData
• Observable Data Holder

• Lifecycle aware

• Automatic subscription management
LiveData<String> stateData = new MutableLiveData<>();
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
stateData.observe((LifecycleOwner) this, ((String) result) -> {
// stateData .
});
}
@Override
protected void onStart() {
super.onStart();
stateData.setValue(“Start");
}
public class StateChangeLiveData extends MutableLiveData<String> {
@Override
protected void onActive() {
super.onActive();

// Active Observer 

// Active: Lifecycle.State STARTED RESUMED
}
@Override
protected void onInactive() {
super.onInactive();

// Active Observer
}
}
ViewModel
public class MyActivity extends LifecycleActivity {
LiveData<User> userData;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
userData = userRepository.fetchData();
userData.observe(this, user -> {
// update UI
});
}
}
StartCreate Resume Pause Stop Destroy
Rotated
fetchData
StartCreate Resume
fetchData
Activity 

.
ViewModel
The ViewModel class is designed to store
and manage UI-related data so that the
data survives configuration changes such
as screen rotations.
”
“
public class UserViewModel extends ViewModel {
}



public class UserViewModel extends AndroidViewModel {

// Application ViewModel

}
ViewModel
• 

• ActivityContext 

• Resource
public class MyActivity extends LifecycleActivity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.insert_activity);


// ViewModelStore ViewModel .
UserListViewModel viewModel = ViewModelProviders.of(this)

.get(UserListViewModel.class);
public class MyActivity extends LifecycleActivity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ViewModelProviders.of(this).get(UserListViewModel.class)
.getData()
.observe(this, user -> {
//update UI
});
public class UserListViewModel extends ViewModel {

private LiveData<User> userLiveData;



public LiveData<User> getData() {

if (userLiveData == null) {

userLiveData = userRepository.fetchData();

}

return userLiveData;

}

}
StartCreate Resume Pause Stop Destroy
Rotated
fetchData
StartCreate Resume
fetchData
StartCreate Resume Pause Stop Destroy
Rotated
StartCreate Resume
ViewModel
fetchData
getData getData
Room
Room
• Sqlite ORM

• Entity

• Dao

• Database
id name create_time
@Entity
public class User {
@PrimaryKey(autoGenerate = true)
private Long id;
String name;
@ColumnInfo(name = "created_time")
private long createdTime;
@Ignore
Bitmap profile;
}
Entity
DAO
@Dao
public interface UserDao {
@Query("SELECT * FROM user")
List<User> getAll();
@Query("SELECT * FROM user WHERE id IN (:userIds)")
List<User> loadAllByIds(int[] userIds);
@Query("SELECT * FROM user WHERE name LIKE :first LIMIT 1")
User findByName(String first);
@Insert(onConflict = OnConflictStrategy.REPLACE)
void insertAll(User... users);
@Delete
void delete(User user);
@Update
void updateUser(User user);
DAO (Rx, LiveData)
@Query("SELECT * FROM user")
LiveData<List<User>> getAllSync();
@Query("SELECT * FROM user WHERE id = :userId")
LiveData<User> fetchUser(String userId);
@Query("SELECT * from user where id = :id LIMIT 1")
Flowable<User> loadUserByIdRx(int id);
@Query("SELECT * FROM user WHERE age > :minAge LIMIT 5")
Cursor loadRawUsersOlderThan(int minAge);
Database
@Database(entities = {User.class, Book.class}, version = 1)
public abstract class AppDatabase extends RoomDatabase {


public abstract UserDao userDao();
public abstract BookDao bookDao();
}
Entity - Embedded
id name created_time image_id image_width image_height
public class Image {
String id;
Integer width;
Integer height;
}
@Entity
public class User {

@PrimaryKey(autoGenerate = true)
private Long id;
String name;


@Embedded(prefix = "image_")
private Image image;
@ColumnInfo(name = "created_time")
private long createdTime;
Entity - TypeConverter
public class User {
@PrimaryKey
private Long id;
@TypeConverters(Converters.class)
private Date date;
public class Converters {
@TypeConverter
public static Date toDate(Long timestamp) {
return timestamp == null ? null : 

new Date(timestamp);
}
@TypeConverter
public static Long toTimestamp(Date date) {
return date == null ? null : date.getTime();
}
}
Entity - Relation
@Entity(indices = {@Index(value = "id", unique = true)}, 

foreignKeys = {
@ForeignKey(entity = Book.class, 

parentColumns = "id", 

childColumns = "bookId", 

onDelete = ForeignKey.CASCADE)
})
public class User {
@PrimaryKey(autoGenerate = true)
private Long id;
public Long bookId;

}
public class UserDao_Impl implements UserDao {
private final RoomDatabase __db;
private final EntityInsertionAdapter __insertionAdapterOfUser;
private final EntityDeletionOrUpdateAdapter __deletionAdapterOfUser;
private final EntityDeletionOrUpdateAdapter __updateAdapterOfUser;
public UserDao_Impl(RoomDatabase __db) {
this.__db = __db;
this.__insertionAdapterOfUser = new EntityInsertionAdapter<User>(__db) {
@Override
public String createQuery() {
return "INSERT OR REPLACE INTO
`User`(`id`,`name`,`created_time`,`updated_time`,`age`,`bookId`,`image_id`,`image_width`,`image_height`) VALUES
(?,?,?,?,?,?,?,?,?)";
}
@Override
public void bind(SupportSQLiteStatement stmt, User value) {
if (value.getId() == null) {
stmt.bindNull(1);
} else {
stmt.bindLong(1, value.getId());
}
if (value.getName() == null) {
stmt.bindNull(2);
} else {
stmt.bindString(2, value.getName());
}
stmt.bindLong(3, value.getCreatedTime());
if (value.getUpdatedTime() == null) {
stmt.bindNull(4);
} else {
stmt.bindLong(4, value.getUpdatedTime());
}
Error
@Query("SELECT * FROM users”)

List<User> getAll();
Architecture Components
• Handling Lifecycles

• LiveData

• ViewModel

• Room
• RxJava

• greenDAO ( Realm)

• MVP

• Firebase, Retrofit, Dagger, ButterKnife, Fresco, Glide, Mockito …
Android Lifecycle Components 

vs 

ReactiveX
public class TestActivity extends RxFragmentActivity {
@Override
protected void onCreate(@Nullable Bundle b) {
super.onCreate(savedInstanceState);
lifecycle()
.filter(e -> e == ActivityEvent.START)
.subscribe(e -> {
// on start
});
}
}
public class TestActivity extends LifecycleActivity
implements LifecycleObserver {
@Override
protected void onCreate(@Nullable Bundle b) {
super.onCreate(savedInstanceState);
getLifecycle().addObserver(this);
}
@OnLifecycleEvent(Lifecycle.Event.ON_START)
void start() {
// on start
}
}
LifecycleOwner RxLifecycle
public abstract class RxFragmentActivity
extends FragmentActivity
implements LifecycleProvider<ActivityEvent> {
private final BehaviorSubject<ActivityEvent> lifecycleSubject
= BehaviorSubject.create();
@Override
@NonNull
@CheckResult
public final Observable<ActivityEvent> lifecycle() {
return lifecycleSubject.asObservable();
}
@Override
@CallSuper
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
lifecycleSubject.onNext(ActivityEvent.CREATE);
}
@Override
@CallSuper
protected void onStart() {
super.onStart();
lifecycleSubject.onNext(ActivityEvent.START);
}
}
public class LifecycleActivity extends FragmentActivity
implements LifecycleRegistryOwner {
private final LifecycleRegistry mRegistry
= new LifecycleRegistry(this);
@Override
public LifecycleRegistry getLifecycle() {
return mRegistry;
}
}
LifecycleActivity RxFragmentActivity
public class TestActivity extends RxFragmentActivity {
@Override
protected void onCreate(@Nullable Bundle b) {
super.onCreate(savedInstanceState);
Flowable<Long> data = getData();
data.compose(RxLifecycle.bindUntilEvent(
lifecycle(), ActivityEvent.DESTROY))
.subscribe(d -> {
// update ui
});
}
}
public class TestActivity extends LifecycleActivity {
@Override
protected void onCreate(@Nullable Bundle b) {
super.onCreate(savedInstanceState);
LiveData<Long> data = getData();
data.observe(this, result -> {
// update ui
});
}
}
LiveData RxFlowable
Don’t migrate from RxJava
But be sure that you correctly handle lifecycle.

”
“
Room vs greenDAO vs Realm
@Entity
public class RoomUser {
@PrimaryKey
private long id;
// getter & setter
}
Room
greenDAO
Realm
@Entity
public class GreenUser {
@Id
private long id;
// getter & setter
}
public class RealmUser extends RealmObject {
@PrimaryKey
private long id;
// getter & setter
}
@Entity(tableName = "user")
public class RoomUser {
@ColumnInfo(name = “first_name")
private String firstName;
}
@Entity(nameInDb = "user")
public class GreenUser {
@Property(nameInDb = “first_name")
private String firstName;
}
Room
greenDAO
Realm
@Entity(indices = @Index(“address"))
public class RoomUser {
private String address;
@Ignore
private String sessionId;
}
@Entity(indexes = @Index("address DESC"))
public class GreenUser {
private String address;
@Transient
private String sessionId;
}
public class RealmUser extends RealmObject {
@Index
private String address;
@Ignore
private String sessionId;
}
Room
greenDAO
Realm
@Dao
public interface RoomUserDao {
@Query("SELECT * FROM RoomUser WHERE id > 10 ORDER BY id DESC”)
List<RoomUser> getUsers();
}
public class GreenUseCase {
public List<GreenUser> getUsers() {
// get DaoSession
return new daoSession.getGreenUserDao().queryBuilder()
.where(GreenUserDao.Properties.Id.gt(10))
.orderDesc(GreenUserDao.Properties.Id)
.list();
}
}
public class RealmUseCase {
public RealmResults<RealmUser> getUsers() {
// get realm instance
return realm.where(RealmUser.class)
.greaterThan("id", 10)
.findAllSorted("id", Sort.DESCENDING);
}
}
Room
greenDAO
Realm
public class AndroidUser {

private String userId;



private String groupID;

}
public class AndroidGroup {



private String groupId;



private String groupName;



private List<AndroidUser> roomUser;

}
Relation
@Entity
public class RoomGroup {
@PrimaryKey
private long id;
}
@Entity(foreignKeys = @ForeignKey(
entity = RoomGroup.class,
parentColumns = "id",
childColumns = "groupId"))
public class RoomUser {
@PrimaryKey
private long id;
private long groupId;
}
https://developer.android.com/topic/libraries/architecture/room.html#no-object-references
Relation - Room
@Dao
public interface RoomGroupDao {
@Insert(onConflict = OnConflictStrategy.REPLACE)
void insertGroup(RoomGroup group);
@Query("SELECT * FROM RoomGroup WHERE id = :id")
LiveData<RoomGroup> getGroup(long id);
}
@Dao
public interface RoomUserDao {
@Insert(onConflict = OnConflictStrategy.REPLACE)
void insertUsers(List<RoomUser> users);
@Query("SELECT * FROM RoomUser WHERE groupId = :groupId")
LiveData<List<RoomUser>> getUsers(long groupId);
}
@Entity
public class GreenGroup {
@Id
private long id;
@ToMany(referencedJoinProperty
= "groupId")
private List<GreenUser> users;
}
@Entity
public class GreenUser {
@Id
private long id;
private long groupId;
}
Relation - greenDAO
public class GreenUseCase {
public void insertGroup(GreenGroup group) {
daoSession.getGreenGroupDao()
.insertOrReplace(group);
daoSession.getGreenUserDao()
.insertOrReplaceInTx(group.getUsers());
}
public GreenGroup getGroup(long groupId) {
return daoSession.getGreenGroupDao()
.queryBuilder()
.where(GreenGroupDao.Properties.Id.eq(groupId))
.build()
.unique();
}
}
public class RealmGroup extends RealmObject {
@PrimaryKey
private long id;
RealmList<RealmUser> users;
}
public class RealmUser extends RealmObject {
@PrimaryKey
private long id;
}
Relation - Realm
public class RealmUseCase {
public void insertGroup(RealmGroup group) {
realm.insertOrUpdate(group);
}
public RealmGroup getGroup(long groupId) {
return realm.where(RealmGroup.class)
.equalTo("id", groupId)
.findFirst();
}
}
Realm GreenDao Room
Core Native Library SQLite SQLite
Performance Realm Realm
Relation


.
QueryBuilder X
DeepInsert X X
LazyLoading X
Integration Rx Rx, LiveData, Cursor
https://youtu.be/FrteWKKVyzI
https://youtu.be/bEKNi1JOrNs
https://youtu.be/MfHsPGQ6bgE
https://developer.android.com/topic/libraries/architecture/index.html
alpaca@vcnc.co.kr
• http://engineering.vcnc.co.kr/jobs/

Architecture Components

  • 1.
  • 2.
  • 3.
    Architecture Components • GoogleI/O 2017 
 Architecture Components - Introduction
 Architecture Components - Solving the Lifecycle
 Architecture Components - Persistence and Offline • • https://developer.android.com/topic/libraries/architecture/ index.html
  • 4.
    Architecture Components • HandlingLifecycles • LiveData • ViewModel • Room
  • 5.
    build.gradle • allprojects {
 repositories{
 jcenter()
 maven { url 'https://maven.google.com' }
 }
 } • compile "android.arch.lifecycle:runtime:1.0.0-alpha3"
 compile "android.arch.lifecycle:extensions:1.0.0-alpha3"
 annotationProcessor "android.arch.lifecycle:compiler:1.0.0-alpha3"
 • compile "android.arch.persistence.room:runtime:1.0.0-alpha3"
 annotationProcessor "android.arch.persistence.room:compiler:1.0.0-alpha3"
 • compile "android.arch.persistence.room:rxjava2:1.0.0-alpha3"
 testCompile "android.arch.persistence.room:testing:1.0.0-alpha3"
  • 6.
  • 7.
    public class MyActivityextends AppCompatActivity { private TestListener testListener; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); testListener = new TestListener(); } @Override protected void onStart() { super.onStart(); testListener.start(); } @Override protected void onStop() { super.onStop(); testListener.stop(); } }
  • 8.
    public class MyActivityextends AppCompatActivity { private TestListener testListener; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); testListener = new TestListener(); } @Override protected void onStart() { super.onStart(); testListener.start(); } @Override protected void onStop() { super.onStop(); testListener.stop(); } } onStart 
 Override .
  • 9.
  • 10.
    Handling Lifecycles • Lifecycle •LifecycleOwner • LifecycleObserver
  • 11.
    public class MyActivityextends LifecycleActivity { @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_lifecycle); TestListener testListener = new TestListener(
 getLifecycle(), 
 result -> { // update UI }); } }
  • 12.
    public class TestListenerimplements LifecycleObserver { private Lifecycle lifecycle; public TestListener(Lifecycle lifecycle, TestCallback callback) { lifecycle.addObserver(this); this.lifecycle = lifecycle; } @OnLifecycleEvent(Lifecycle.Event.ON_START) void start() { // start Event } @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY) void clean() { lifecycle.removeObserver(this); } }
  • 13.
    public class MyActivityextends CustomActivity { @Override
 protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 setContentView(R.layout.activity_main);
 } }
  • 14.
    public class LifecycleActivityextends FragmentActivity 
 implements LifecycleRegistryOwner { private final LifecycleRegistry mRegistry 
 = new LifecycleRegistry(this); @Override public LifecycleRegistry getLifecycle() { return mRegistry; } }
  • 15.
    public class MyActivityextends CustomActivity implements LifecycleRegistryOwner { private final LifecycleRegistry lifecycleRegistry = new LifecycleRegistry(this); @Override public LifecycleRegistry getLifecycle() { return lifecycleRegistry; } @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_lifecycle); TestListener testListener = new TestListener(getLifecycle(), state -> { // update Ui }); } }
  • 17.
    public class MyActivityextends LifecycleActivity { private TestListener testListener; @Override protected void onStart() { super.onStart(); Utils.checkUserStatus(state -> { if (state.equals("OK")) { testListener.start(); } }); }
  • 18.
    public class MyActivityextends LifecycleActivity { private TestListener testListener; @Override protected void onStart() { super.onStart(); // ? Utils.checkUserStatus(state -> { if (state.equals("OK")) { testListener.start(); } }); }
  • 19.
    StartCreate Resume PauseStop Destroy testListener.stop Utils.checkStatus testListener.start
  • 20.
  • 21.
    public class MyActivityextends LifecycleActivity { private TestListener testListener; @Override protected void onStart() { super.onStart(); Utils.checkUserStatus(state -> { if (state.equals("OK") && getLifecycle()
 .getCurrentState()
 .isAtLeast(Lifecycle.State.STARTED)) { testListener.start(); } }); }
  • 22.
  • 23.
    LiveData • Observable DataHolder • Lifecycle aware • Automatic subscription management
  • 24.
    LiveData<String> stateData =new MutableLiveData<>(); @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); stateData.observe((LifecycleOwner) this, ((String) result) -> { // stateData . }); } @Override protected void onStart() { super.onStart(); stateData.setValue(“Start"); }
  • 25.
    public class StateChangeLiveDataextends MutableLiveData<String> { @Override protected void onActive() { super.onActive();
 // Active Observer 
 // Active: Lifecycle.State STARTED RESUMED } @Override protected void onInactive() { super.onInactive();
 // Active Observer } }
  • 26.
  • 27.
    public class MyActivityextends LifecycleActivity { LiveData<User> userData; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); userData = userRepository.fetchData(); userData.observe(this, user -> { // update UI }); } }
  • 28.
    StartCreate Resume PauseStop Destroy Rotated fetchData StartCreate Resume fetchData
  • 29.
  • 30.
    ViewModel The ViewModel classis designed to store and manage UI-related data so that the data survives configuration changes such as screen rotations. ” “
  • 31.
    public class UserViewModelextends ViewModel { }
 
 public class UserViewModel extends AndroidViewModel {
 // Application ViewModel
 }
  • 32.
  • 33.
    public class MyActivityextends LifecycleActivity { @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.insert_activity); 
 // ViewModelStore ViewModel . UserListViewModel viewModel = ViewModelProviders.of(this)
 .get(UserListViewModel.class);
  • 34.
    public class MyActivityextends LifecycleActivity { @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); ViewModelProviders.of(this).get(UserListViewModel.class) .getData() .observe(this, user -> { //update UI }); public class UserListViewModel extends ViewModel {
 private LiveData<User> userLiveData;
 
 public LiveData<User> getData() {
 if (userLiveData == null) {
 userLiveData = userRepository.fetchData();
 }
 return userLiveData;
 }
 }
  • 35.
    StartCreate Resume PauseStop Destroy Rotated fetchData StartCreate Resume fetchData
  • 36.
    StartCreate Resume PauseStop Destroy Rotated StartCreate Resume ViewModel fetchData getData getData
  • 37.
  • 38.
    Room • Sqlite ORM •Entity • Dao • Database
  • 39.
    id name create_time @Entity publicclass User { @PrimaryKey(autoGenerate = true) private Long id; String name; @ColumnInfo(name = "created_time") private long createdTime; @Ignore Bitmap profile; } Entity
  • 40.
    DAO @Dao public interface UserDao{ @Query("SELECT * FROM user") List<User> getAll(); @Query("SELECT * FROM user WHERE id IN (:userIds)") List<User> loadAllByIds(int[] userIds); @Query("SELECT * FROM user WHERE name LIKE :first LIMIT 1") User findByName(String first); @Insert(onConflict = OnConflictStrategy.REPLACE) void insertAll(User... users); @Delete void delete(User user); @Update void updateUser(User user);
  • 41.
    DAO (Rx, LiveData) @Query("SELECT* FROM user") LiveData<List<User>> getAllSync(); @Query("SELECT * FROM user WHERE id = :userId") LiveData<User> fetchUser(String userId); @Query("SELECT * from user where id = :id LIMIT 1") Flowable<User> loadUserByIdRx(int id); @Query("SELECT * FROM user WHERE age > :minAge LIMIT 5") Cursor loadRawUsersOlderThan(int minAge);
  • 42.
    Database @Database(entities = {User.class,Book.class}, version = 1) public abstract class AppDatabase extends RoomDatabase { 
 public abstract UserDao userDao(); public abstract BookDao bookDao(); }
  • 43.
    Entity - Embedded idname created_time image_id image_width image_height public class Image { String id; Integer width; Integer height; } @Entity public class User {
 @PrimaryKey(autoGenerate = true) private Long id; String name; 
 @Embedded(prefix = "image_") private Image image; @ColumnInfo(name = "created_time") private long createdTime;
  • 44.
    Entity - TypeConverter publicclass User { @PrimaryKey private Long id; @TypeConverters(Converters.class) private Date date; public class Converters { @TypeConverter public static Date toDate(Long timestamp) { return timestamp == null ? null : 
 new Date(timestamp); } @TypeConverter public static Long toTimestamp(Date date) { return date == null ? null : date.getTime(); } }
  • 45.
    Entity - Relation @Entity(indices= {@Index(value = "id", unique = true)}, 
 foreignKeys = { @ForeignKey(entity = Book.class, 
 parentColumns = "id", 
 childColumns = "bookId", 
 onDelete = ForeignKey.CASCADE) }) public class User { @PrimaryKey(autoGenerate = true) private Long id; public Long bookId;
 }
  • 46.
    public class UserDao_Implimplements UserDao { private final RoomDatabase __db; private final EntityInsertionAdapter __insertionAdapterOfUser; private final EntityDeletionOrUpdateAdapter __deletionAdapterOfUser; private final EntityDeletionOrUpdateAdapter __updateAdapterOfUser; public UserDao_Impl(RoomDatabase __db) { this.__db = __db; this.__insertionAdapterOfUser = new EntityInsertionAdapter<User>(__db) { @Override public String createQuery() { return "INSERT OR REPLACE INTO `User`(`id`,`name`,`created_time`,`updated_time`,`age`,`bookId`,`image_id`,`image_width`,`image_height`) VALUES (?,?,?,?,?,?,?,?,?)"; } @Override public void bind(SupportSQLiteStatement stmt, User value) { if (value.getId() == null) { stmt.bindNull(1); } else { stmt.bindLong(1, value.getId()); } if (value.getName() == null) { stmt.bindNull(2); } else { stmt.bindString(2, value.getName()); } stmt.bindLong(3, value.getCreatedTime()); if (value.getUpdatedTime() == null) { stmt.bindNull(4); } else { stmt.bindLong(4, value.getUpdatedTime()); }
  • 47.
    Error @Query("SELECT * FROMusers”)
 List<User> getAll();
  • 48.
    Architecture Components • HandlingLifecycles • LiveData • ViewModel • Room
  • 49.
    • RxJava • greenDAO( Realm) • MVP • Firebase, Retrofit, Dagger, ButterKnife, Fresco, Glide, Mockito …
  • 50.
    Android Lifecycle Components
 vs 
 ReactiveX
  • 51.
    public class TestActivityextends RxFragmentActivity { @Override protected void onCreate(@Nullable Bundle b) { super.onCreate(savedInstanceState); lifecycle() .filter(e -> e == ActivityEvent.START) .subscribe(e -> { // on start }); } } public class TestActivity extends LifecycleActivity implements LifecycleObserver { @Override protected void onCreate(@Nullable Bundle b) { super.onCreate(savedInstanceState); getLifecycle().addObserver(this); } @OnLifecycleEvent(Lifecycle.Event.ON_START) void start() { // on start } } LifecycleOwner RxLifecycle
  • 52.
    public abstract classRxFragmentActivity extends FragmentActivity implements LifecycleProvider<ActivityEvent> { private final BehaviorSubject<ActivityEvent> lifecycleSubject = BehaviorSubject.create(); @Override @NonNull @CheckResult public final Observable<ActivityEvent> lifecycle() { return lifecycleSubject.asObservable(); } @Override @CallSuper protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); lifecycleSubject.onNext(ActivityEvent.CREATE); } @Override @CallSuper protected void onStart() { super.onStart(); lifecycleSubject.onNext(ActivityEvent.START); } } public class LifecycleActivity extends FragmentActivity implements LifecycleRegistryOwner { private final LifecycleRegistry mRegistry = new LifecycleRegistry(this); @Override public LifecycleRegistry getLifecycle() { return mRegistry; } } LifecycleActivity RxFragmentActivity
  • 53.
    public class TestActivityextends RxFragmentActivity { @Override protected void onCreate(@Nullable Bundle b) { super.onCreate(savedInstanceState); Flowable<Long> data = getData(); data.compose(RxLifecycle.bindUntilEvent( lifecycle(), ActivityEvent.DESTROY)) .subscribe(d -> { // update ui }); } } public class TestActivity extends LifecycleActivity { @Override protected void onCreate(@Nullable Bundle b) { super.onCreate(savedInstanceState); LiveData<Long> data = getData(); data.observe(this, result -> { // update ui }); } } LiveData RxFlowable
  • 54.
    Don’t migrate fromRxJava But be sure that you correctly handle lifecycle.
 ” “
  • 55.
  • 56.
    @Entity public class RoomUser{ @PrimaryKey private long id; // getter & setter } Room greenDAO Realm @Entity public class GreenUser { @Id private long id; // getter & setter } public class RealmUser extends RealmObject { @PrimaryKey private long id; // getter & setter }
  • 57.
    @Entity(tableName = "user") publicclass RoomUser { @ColumnInfo(name = “first_name") private String firstName; } @Entity(nameInDb = "user") public class GreenUser { @Property(nameInDb = “first_name") private String firstName; } Room greenDAO Realm
  • 58.
    @Entity(indices = @Index(“address")) publicclass RoomUser { private String address; @Ignore private String sessionId; } @Entity(indexes = @Index("address DESC")) public class GreenUser { private String address; @Transient private String sessionId; } public class RealmUser extends RealmObject { @Index private String address; @Ignore private String sessionId; } Room greenDAO Realm
  • 59.
    @Dao public interface RoomUserDao{ @Query("SELECT * FROM RoomUser WHERE id > 10 ORDER BY id DESC”) List<RoomUser> getUsers(); } public class GreenUseCase { public List<GreenUser> getUsers() { // get DaoSession return new daoSession.getGreenUserDao().queryBuilder() .where(GreenUserDao.Properties.Id.gt(10)) .orderDesc(GreenUserDao.Properties.Id) .list(); } } public class RealmUseCase { public RealmResults<RealmUser> getUsers() { // get realm instance return realm.where(RealmUser.class) .greaterThan("id", 10) .findAllSorted("id", Sort.DESCENDING); } } Room greenDAO Realm
  • 60.
    public class AndroidUser{
 private String userId;
 
 private String groupID;
 } public class AndroidGroup {
 
 private String groupId;
 
 private String groupName;
 
 private List<AndroidUser> roomUser;
 } Relation
  • 61.
    @Entity public class RoomGroup{ @PrimaryKey private long id; } @Entity(foreignKeys = @ForeignKey( entity = RoomGroup.class, parentColumns = "id", childColumns = "groupId")) public class RoomUser { @PrimaryKey private long id; private long groupId; } https://developer.android.com/topic/libraries/architecture/room.html#no-object-references Relation - Room @Dao public interface RoomGroupDao { @Insert(onConflict = OnConflictStrategy.REPLACE) void insertGroup(RoomGroup group); @Query("SELECT * FROM RoomGroup WHERE id = :id") LiveData<RoomGroup> getGroup(long id); } @Dao public interface RoomUserDao { @Insert(onConflict = OnConflictStrategy.REPLACE) void insertUsers(List<RoomUser> users); @Query("SELECT * FROM RoomUser WHERE groupId = :groupId") LiveData<List<RoomUser>> getUsers(long groupId); }
  • 62.
    @Entity public class GreenGroup{ @Id private long id; @ToMany(referencedJoinProperty = "groupId") private List<GreenUser> users; } @Entity public class GreenUser { @Id private long id; private long groupId; } Relation - greenDAO public class GreenUseCase { public void insertGroup(GreenGroup group) { daoSession.getGreenGroupDao() .insertOrReplace(group); daoSession.getGreenUserDao() .insertOrReplaceInTx(group.getUsers()); } public GreenGroup getGroup(long groupId) { return daoSession.getGreenGroupDao() .queryBuilder() .where(GreenGroupDao.Properties.Id.eq(groupId)) .build() .unique(); } }
  • 63.
    public class RealmGroupextends RealmObject { @PrimaryKey private long id; RealmList<RealmUser> users; } public class RealmUser extends RealmObject { @PrimaryKey private long id; } Relation - Realm public class RealmUseCase { public void insertGroup(RealmGroup group) { realm.insertOrUpdate(group); } public RealmGroup getGroup(long groupId) { return realm.where(RealmGroup.class) .equalTo("id", groupId) .findFirst(); } }
  • 64.
    Realm GreenDao Room CoreNative Library SQLite SQLite Performance Realm Realm Relation 
 . QueryBuilder X DeepInsert X X LazyLoading X Integration Rx Rx, LiveData, Cursor
  • 65.
  • 66.