SlideShare a Scribd company logo
ANDROID
ARCHITECTURE
COMPONENTS -
INTRODUCTION
Paulina Szklarska
Hello!
Nice to meet you
Paulina Szklarska
• Android Developer
• co-organizer of Toast Wrocław meetups
• cat owner/travel enthusiast
@pszklarska
@pszklarska
@p_szklarska
1.
INTRO
What are
Architecture
Components?
MVP
MVVM
MVC
VIPER
CLEAN
ARCHITECTURE
MVI
MV-ANYTHING
ARCHITECTURES
?
“
Why there is no official
architecture guide in Android
documentation?
~ me, some time ago
Before
May 2017
https://plus.google.com/+DianneHackborn/posts/FXCCYxepsDU
„Should you use MVC? Or MVP? Or
MVVM? I have no idea. Heck, I only know
about MVC from school and had to do a
Google search to find other options to put
here.”
~ Dianne Hackborn,
Android Framework Engineer,
May 2016
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
public class Cat {

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

public class Cat {

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

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
public interface CatDao {



}a
@Dao

public interface CatDao {



}a
@Dao

public interface CatDao {



@Insert

void insert(Cat... cats);



@Update

void update(Cat... cats);



@Delete

void delete(Cat... cats);

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



}a
@Dao

public interface CatDao {



@Insert

void insert(Cat... cats);



@Insert

void insert(Cat cat);



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

}a
@Dao

public interface CatDao {



@Query("SELECT * FROM kittens")

List<Cat> getAllCats();



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

Cat getCatById(int id);



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



}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
public class CatDatabase {



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

public class CatDatabase {



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

public abstract class CatDatabase extends RoomDatabase {



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

public abstract class CatDatabase extends RoomDatabase {



public abstract CatDao getCatDao();

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

public abstract class CatDatabase extends RoomDatabase {



private static CatDatabase create(final Context context) {

return Room.databaseBuilder(
context,
CatDatabase.class,
"catsDatabase.db")

.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

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
@Entity(foreignKeys = @ForeignKey(entity = Owner.class))

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
@Entity(foreignKeys = @ForeignKey(entity = Owner.class,

parentColumns = "id"))

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
@Entity(foreignKeys = @ForeignKey(entity = Owner.class,

parentColumns = "id",

childColumns = "ownerId"))

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
@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)

public abstract class CatDatabase extends RoomDatabase {



}a
@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)

.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)
.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)

.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,

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

}a
@After

public void closeDb() throws IOException {

database.close();

}a

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

}a



@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();

}a

}a
tl;dr • 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 {



public LocationManager() {

// do something

}a



void addLocationListener() {

// register location manager listener

}a


void removeLocationListener() {

// remove location manager listener

}a

}a
public class LocationManager implements LifecycleObserver {



public LocationManager() {
// do something 

}a



void addLocationListener() {

// register location manager listener

}a



void removeLocationListener() {

// remove location manager listener

}a

}a
public class LocationManager implements LifecycleObserver {



public LocationManager(LifecycleOwner lifecycleOwner) {
// do something 

lifecycleOwner.getLifecycle().addObserver(this);

}a



void addLocationListener() {

// register location manager listener

}a



void removeLocationListener() {

// remove location manager listener

}a

}a
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



void removeLocationListener() {

// remove location manager listener

}a

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


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



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



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 List<User> userList;



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 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 LiveData<List<User>> getUserList() {

return userList;

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



showUsers(usersViewModel.getUserList());

}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

Lowering in C#: What really happens with your code?, from NDC Oslo 2019
Lowering in C#: What really happens with your code?, from NDC Oslo 2019Lowering in C#: What really happens with your code?, from NDC Oslo 2019
Lowering in C#: What really happens with your code?, from NDC Oslo 2019
David Wengier
 
An introduction into Spring Data
An introduction into Spring DataAn introduction into Spring Data
An introduction into Spring Data
Oliver Gierke
 
Asp.net create delete directory folder in c# vb.net
Asp.net   create delete directory folder in c# vb.netAsp.net   create delete directory folder in c# vb.net
Asp.net create delete directory folder in c# vb.netrelekarsushant
 
Spring Data JPA from 0-100 in 60 minutes
Spring Data JPA from 0-100 in 60 minutesSpring Data JPA from 0-100 in 60 minutes
Spring Data JPA from 0-100 in 60 minutes
VMware Tanzu
 
スゴイ django - Python&Djangoで始めるWeb開発 in 札幌 #1
スゴイ django - Python&Djangoで始めるWeb開発 in 札幌 #1スゴイ django - Python&Djangoで始めるWeb開発 in 札幌 #1
スゴイ django - Python&Djangoで始めるWeb開発 in 札幌 #1
makoto tsuyuki
 
JDBC - JPA - Spring Data
JDBC - JPA - Spring DataJDBC - JPA - Spring Data
JDBC - JPA - Spring Data
Arturs Drozdovs
 
Solving the Riddle of Search: Using Sphinx with Rails
Solving the Riddle of Search: Using Sphinx with RailsSolving the Riddle of Search: Using Sphinx with Rails
Solving the Riddle of Search: Using Sphinx with Rails
freelancing_god
 
Open Hack NYC Yahoo Social SDKs
Open Hack NYC Yahoo Social SDKsOpen Hack NYC Yahoo Social SDKs
Open Hack NYC Yahoo Social SDKs
Dustin Whittle
 
#살아있다 #자프링외길12년차 #코프링2개월생존기
#살아있다 #자프링외길12년차 #코프링2개월생존기#살아있다 #자프링외길12년차 #코프링2개월생존기
#살아있다 #자프링외길12년차 #코프링2개월생존기
Arawn Park
 
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
 
Guice2.0
Guice2.0Guice2.0
Test du futur avec Spock
Test du futur avec SpockTest du futur avec Spock
Test du futur avec Spock
CARA_Lyon
 
Functionality Focused Code Organization
Functionality Focused Code OrganizationFunctionality Focused Code Organization
Functionality Focused Code Organization
Rebecca Murphey
 
Pro bun-fighting - Working with JavaScript projects
Pro bun-fighting - Working with JavaScript projectsPro bun-fighting - Working with JavaScript projects
Pro bun-fighting - Working with JavaScript projects
Frances Berriman
 
GreenDao Introduction
GreenDao IntroductionGreenDao Introduction
GreenDao Introduction
Booch Lin
 
A evolução da persistência de dados (com sqlite) no android
A evolução da persistência de dados (com sqlite) no androidA evolução da persistência de dados (com sqlite) no android
A evolução da persistência de dados (com sqlite) no android
Rodrigo de Souza Castro
 
Java → kotlin: Tests Made Simple
Java → kotlin: Tests Made SimpleJava → kotlin: Tests Made Simple
Java → kotlin: Tests Made Simple
leonsabr
 
Wroclaw GraphQL - GraphQL in Java
Wroclaw GraphQL - GraphQL in JavaWroclaw GraphQL - GraphQL in Java
Wroclaw GraphQL - GraphQL in Java
MarcinStachniuk
 

What's hot (20)

Lowering in C#: What really happens with your code?, from NDC Oslo 2019
Lowering in C#: What really happens with your code?, from NDC Oslo 2019Lowering in C#: What really happens with your code?, from NDC Oslo 2019
Lowering in C#: What really happens with your code?, from NDC Oslo 2019
 
An introduction into Spring Data
An introduction into Spring DataAn introduction into Spring Data
An introduction into Spring Data
 
Asp.net create delete directory folder in c# vb.net
Asp.net   create delete directory folder in c# vb.netAsp.net   create delete directory folder in c# vb.net
Asp.net create delete directory folder in c# vb.net
 
Spring Data JPA from 0-100 in 60 minutes
Spring Data JPA from 0-100 in 60 minutesSpring Data JPA from 0-100 in 60 minutes
Spring Data JPA from 0-100 in 60 minutes
 
スゴイ django - Python&Djangoで始めるWeb開発 in 札幌 #1
スゴイ django - Python&Djangoで始めるWeb開発 in 札幌 #1スゴイ django - Python&Djangoで始めるWeb開発 in 札幌 #1
スゴイ django - Python&Djangoで始めるWeb開発 in 札幌 #1
 
JDBC - JPA - Spring Data
JDBC - JPA - Spring DataJDBC - JPA - Spring Data
JDBC - JPA - Spring Data
 
Solving the Riddle of Search: Using Sphinx with Rails
Solving the Riddle of Search: Using Sphinx with RailsSolving the Riddle of Search: Using Sphinx with Rails
Solving the Riddle of Search: Using Sphinx with Rails
 
Open Hack NYC Yahoo Social SDKs
Open Hack NYC Yahoo Social SDKsOpen Hack NYC Yahoo Social SDKs
Open Hack NYC Yahoo Social SDKs
 
greenDAO
greenDAOgreenDAO
greenDAO
 
#살아있다 #자프링외길12년차 #코프링2개월생존기
#살아있다 #자프링외길12년차 #코프링2개월생존기#살아있다 #자프링외길12년차 #코프링2개월생존기
#살아있다 #자프링외길12년차 #코프링2개월생존기
 
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!
 
Guice2.0
Guice2.0Guice2.0
Guice2.0
 
Test du futur avec Spock
Test du futur avec SpockTest du futur avec Spock
Test du futur avec Spock
 
Functionality Focused Code Organization
Functionality Focused Code OrganizationFunctionality Focused Code Organization
Functionality Focused Code Organization
 
Pro bun-fighting - Working with JavaScript projects
Pro bun-fighting - Working with JavaScript projectsPro bun-fighting - Working with JavaScript projects
Pro bun-fighting - Working with JavaScript projects
 
GreenDao Introduction
GreenDao IntroductionGreenDao Introduction
GreenDao Introduction
 
A evolução da persistência de dados (com sqlite) no android
A evolução da persistência de dados (com sqlite) no androidA evolução da persistência de dados (com sqlite) no android
A evolução da persistência de dados (com sqlite) no android
 
Green dao
Green daoGreen dao
Green dao
 
Java → kotlin: Tests Made Simple
Java → kotlin: Tests Made SimpleJava → kotlin: Tests Made Simple
Java → kotlin: Tests Made Simple
 
Wroclaw GraphQL - GraphQL in Java
Wroclaw GraphQL - GraphQL in JavaWroclaw GraphQL - GraphQL in Java
Wroclaw GraphQL - GraphQL in Java
 

Similar to Architecure components by Paulina Szklarska

[2019] PAYCO 매거진 서버 Kotlin 적용기
[2019] PAYCO 매거진 서버 Kotlin 적용기[2019] PAYCO 매거진 서버 Kotlin 적용기
[2019] PAYCO 매거진 서버 Kotlin 적용기
NHN FORWARD
 
Creating a Facebook Clone - Part XIX - Transcript.pdf
Creating a Facebook Clone - Part XIX - Transcript.pdfCreating a Facebook Clone - Part XIX - Transcript.pdf
Creating a Facebook Clone - Part XIX - Transcript.pdf
ShaiAlmog1
 
Requery overview
Requery overviewRequery overview
Requery overview
Sunghyouk Bae
 
Green dao 3.0
Green dao 3.0Green dao 3.0
Green dao 3.0
彥彬 洪
 
CDI e as ideias pro futuro do VRaptor
CDI e as ideias pro futuro do VRaptorCDI e as ideias pro futuro do VRaptor
CDI e as ideias pro futuro do VRaptor
Caelum
 
Introducing CakeEntity
Introducing CakeEntityIntroducing CakeEntity
Introducing CakeEntity
Basuke Suzuki
 
NoSQL Endgame Percona Live Online 2020
NoSQL Endgame Percona Live Online 2020NoSQL Endgame Percona Live Online 2020
NoSQL Endgame Percona Live Online 2020
Thodoris Bais
 
Creating a Facebook Clone - Part XIX.pdf
Creating a Facebook Clone - Part XIX.pdfCreating a Facebook Clone - Part XIX.pdf
Creating a Facebook Clone - Part XIX.pdf
ShaiAlmog1
 
Persisting Data on SQLite using Room
Persisting Data on SQLite using RoomPersisting Data on SQLite using Room
Persisting Data on SQLite using Room
Nelson Glauber Leal
 
03 Object Relational Mapping
03 Object Relational Mapping03 Object Relational Mapping
03 Object Relational MappingRanjan Kumar
 
Create an advance data type to represent web page history. Name this .pdf
Create an advance data type to represent web page history. Name this .pdfCreate an advance data type to represent web page history. Name this .pdf
Create an advance data type to represent web page history. Name this .pdf
sanuoptical
 
Introduction to Spring Boot.pdf
Introduction to Spring Boot.pdfIntroduction to Spring Boot.pdf
Introduction to Spring Boot.pdf
ShaiAlmog1
 
Java2
Java2Java2
Annotation processing and code gen
Annotation processing and code genAnnotation processing and code gen
Annotation processing and code gen
koji lin
 
Kotlin Data Model
Kotlin Data ModelKotlin Data Model
Kotlin Data Model
Kros Huang
 
Introducing CakeEntity
Introducing CakeEntityIntroducing CakeEntity
Introducing CakeEntity
Basuke Suzuki
 
Webinar: MongoDB Persistence with Java and Morphia
Webinar: MongoDB Persistence with Java and MorphiaWebinar: MongoDB Persistence with Java and Morphia
Webinar: MongoDB Persistence with Java and Morphia
MongoDB
 
Developing Useful APIs
Developing Useful APIsDeveloping Useful APIs
Developing Useful APIsDmitry Buzdin
 
Zend Framework and the Doctrine2 MongoDB ODM (ZF1)
Zend Framework and the Doctrine2 MongoDB ODM (ZF1)Zend Framework and the Doctrine2 MongoDB ODM (ZF1)
Zend Framework and the Doctrine2 MongoDB ODM (ZF1)
Ryan Mauger
 
AST Transformations at JFokus
AST Transformations at JFokusAST Transformations at JFokus
AST Transformations at JFokusHamletDRC
 

Similar to Architecure components by Paulina Szklarska (20)

[2019] PAYCO 매거진 서버 Kotlin 적용기
[2019] PAYCO 매거진 서버 Kotlin 적용기[2019] PAYCO 매거진 서버 Kotlin 적용기
[2019] PAYCO 매거진 서버 Kotlin 적용기
 
Creating a Facebook Clone - Part XIX - Transcript.pdf
Creating a Facebook Clone - Part XIX - Transcript.pdfCreating a Facebook Clone - Part XIX - Transcript.pdf
Creating a Facebook Clone - Part XIX - Transcript.pdf
 
Requery overview
Requery overviewRequery overview
Requery overview
 
Green dao 3.0
Green dao 3.0Green dao 3.0
Green dao 3.0
 
CDI e as ideias pro futuro do VRaptor
CDI e as ideias pro futuro do VRaptorCDI e as ideias pro futuro do VRaptor
CDI e as ideias pro futuro do VRaptor
 
Introducing CakeEntity
Introducing CakeEntityIntroducing CakeEntity
Introducing CakeEntity
 
NoSQL Endgame Percona Live Online 2020
NoSQL Endgame Percona Live Online 2020NoSQL Endgame Percona Live Online 2020
NoSQL Endgame Percona Live Online 2020
 
Creating a Facebook Clone - Part XIX.pdf
Creating a Facebook Clone - Part XIX.pdfCreating a Facebook Clone - Part XIX.pdf
Creating a Facebook Clone - Part XIX.pdf
 
Persisting Data on SQLite using Room
Persisting Data on SQLite using RoomPersisting Data on SQLite using Room
Persisting Data on SQLite using Room
 
03 Object Relational Mapping
03 Object Relational Mapping03 Object Relational Mapping
03 Object Relational Mapping
 
Create an advance data type to represent web page history. Name this .pdf
Create an advance data type to represent web page history. Name this .pdfCreate an advance data type to represent web page history. Name this .pdf
Create an advance data type to represent web page history. Name this .pdf
 
Introduction to Spring Boot.pdf
Introduction to Spring Boot.pdfIntroduction to Spring Boot.pdf
Introduction to Spring Boot.pdf
 
Java2
Java2Java2
Java2
 
Annotation processing and code gen
Annotation processing and code genAnnotation processing and code gen
Annotation processing and code gen
 
Kotlin Data Model
Kotlin Data ModelKotlin Data Model
Kotlin Data Model
 
Introducing CakeEntity
Introducing CakeEntityIntroducing CakeEntity
Introducing CakeEntity
 
Webinar: MongoDB Persistence with Java and Morphia
Webinar: MongoDB Persistence with Java and MorphiaWebinar: MongoDB Persistence with Java and Morphia
Webinar: MongoDB Persistence with Java and Morphia
 
Developing Useful APIs
Developing Useful APIsDeveloping Useful APIs
Developing Useful APIs
 
Zend Framework and the Doctrine2 MongoDB ODM (ZF1)
Zend Framework and the Doctrine2 MongoDB ODM (ZF1)Zend Framework and the Doctrine2 MongoDB ODM (ZF1)
Zend Framework and the Doctrine2 MongoDB ODM (ZF1)
 
AST Transformations at JFokus
AST Transformations at JFokusAST Transformations at JFokus
AST Transformations at JFokus
 

More from Women in Technology Poland

Get Inspired: Po co nam UX? O edukacji i nie tylko
Get Inspired: Po co nam UX? O edukacji i nie tylkoGet Inspired: Po co nam UX? O edukacji i nie tylko
Get Inspired: Po co nam UX? O edukacji i nie tylko
Women in Technology Poland
 
Pierwsze kroki w karierze IT: LinkedIn - wykorzystaj potencjał sieci
Pierwsze kroki w karierze IT: LinkedIn - wykorzystaj potencjał sieciPierwsze kroki w karierze IT: LinkedIn - wykorzystaj potencjał sieci
Pierwsze kroki w karierze IT: LinkedIn - wykorzystaj potencjał sieci
Women in Technology Poland
 
Tech 101: Scrum 25.04.19 Warszawa
Tech 101: Scrum 25.04.19 WarszawaTech 101: Scrum 25.04.19 Warszawa
Tech 101: Scrum 25.04.19 Warszawa
Women in Technology Poland
 
ARKit by Magdalena Pałka
ARKit by Magdalena PałkaARKit by Magdalena Pałka
ARKit by Magdalena Pałka
Women in Technology Poland
 
React Native by Artur Staszczyk
React Native by Artur StaszczykReact Native by Artur Staszczyk
React Native by Artur Staszczyk
Women in Technology Poland
 
Big Data - historia i przyszłość
Big Data - historia i przyszłośćBig Data - historia i przyszłość
Big Data - historia i przyszłość
Women in Technology Poland
 
Blockchain and Cryptocurrency Basics- #43 spotkanie WiT Kraków
Blockchain and Cryptocurrency Basics- #43 spotkanie WiT KrakówBlockchain and Cryptocurrency Basics- #43 spotkanie WiT Kraków
Blockchain and Cryptocurrency Basics- #43 spotkanie WiT Kraków
Women in Technology Poland
 
"Wyzwania automatyzacji w ciągłej integracji" - o tworzeniu i utrzymaniu test...
"Wyzwania automatyzacji w ciągłej integracji" - o tworzeniu i utrzymaniu test..."Wyzwania automatyzacji w ciągłej integracji" - o tworzeniu i utrzymaniu test...
"Wyzwania automatyzacji w ciągłej integracji" - o tworzeniu i utrzymaniu test...
Women in Technology Poland
 
Agnieszka Pocha - Od surowych danych do gotowego modelu - uczenie maszynowe w...
Agnieszka Pocha - Od surowych danych do gotowego modelu - uczenie maszynowe w...Agnieszka Pocha - Od surowych danych do gotowego modelu - uczenie maszynowe w...
Agnieszka Pocha - Od surowych danych do gotowego modelu - uczenie maszynowe w...
Women in Technology Poland
 
Monika Synoradzka - 10 sposobów na budowę silnego zespołu i bycie dobrym lide...
Monika Synoradzka - 10 sposobów na budowę silnego zespołu i bycie dobrym lide...Monika Synoradzka - 10 sposobów na budowę silnego zespołu i bycie dobrym lide...
Monika Synoradzka - 10 sposobów na budowę silnego zespołu i bycie dobrym lide...
Women in Technology Poland
 
Kulisy pracy w IT: Zawód Front- end Developer prezentacja Pawła Janasa
Kulisy pracy w IT: Zawód Front- end Developer prezentacja Pawła JanasaKulisy pracy w IT: Zawód Front- end Developer prezentacja Pawła Janasa
Kulisy pracy w IT: Zawód Front- end Developer prezentacja Pawła Janasa
Women in Technology Poland
 
Jak bardzo techniczny musi być tester?
Jak bardzo techniczny musi być tester?Jak bardzo techniczny musi być tester?
Jak bardzo techniczny musi być tester?
Women in Technology Poland
 
Poznaj GITa - Natalia Stanko
Poznaj GITa - Natalia StankoPoznaj GITa - Natalia Stanko
Poznaj GITa - Natalia Stanko
Women in Technology Poland
 
Poznaj GITa - część teoretyczna - Anna Szwiec
Poznaj GITa -  część teoretyczna - Anna SzwiecPoznaj GITa -  część teoretyczna - Anna Szwiec
Poznaj GITa - część teoretyczna - Anna Szwiec
Women in Technology Poland
 
HTML, CSS & Javascript Architecture (extended version) - Jan Kraus
HTML, CSS & Javascript Architecture (extended version) - Jan KrausHTML, CSS & Javascript Architecture (extended version) - Jan Kraus
HTML, CSS & Javascript Architecture (extended version) - Jan Kraus
Women in Technology Poland
 
Architektura html, css i javascript - Jan Kraus
Architektura html, css i javascript - Jan KrausArchitektura html, css i javascript - Jan Kraus
Architektura html, css i javascript - Jan Kraus
Women in Technology Poland
 
Hackerspace Wrocław
Hackerspace WrocławHackerspace Wrocław
Hackerspace Wrocław
Women in Technology Poland
 
Roman Czarko-Wasiutycz- Projektowanie baz danych
Roman Czarko-Wasiutycz- Projektowanie baz danychRoman Czarko-Wasiutycz- Projektowanie baz danych
Roman Czarko-Wasiutycz- Projektowanie baz danych
Women in Technology Poland
 
Justyna Hankiewicz- Jak zbudować efektywny zespół
Justyna Hankiewicz- Jak zbudować efektywny zespółJustyna Hankiewicz- Jak zbudować efektywny zespół
Justyna Hankiewicz- Jak zbudować efektywny zespół
Women in Technology Poland
 
Warsztaty o zdrowiu karolina jarosz trener personalny
Warsztaty o zdrowiu   karolina jarosz trener personalnyWarsztaty o zdrowiu   karolina jarosz trener personalny
Warsztaty o zdrowiu karolina jarosz trener personalny
Women in Technology Poland
 

More from Women in Technology Poland (20)

Get Inspired: Po co nam UX? O edukacji i nie tylko
Get Inspired: Po co nam UX? O edukacji i nie tylkoGet Inspired: Po co nam UX? O edukacji i nie tylko
Get Inspired: Po co nam UX? O edukacji i nie tylko
 
Pierwsze kroki w karierze IT: LinkedIn - wykorzystaj potencjał sieci
Pierwsze kroki w karierze IT: LinkedIn - wykorzystaj potencjał sieciPierwsze kroki w karierze IT: LinkedIn - wykorzystaj potencjał sieci
Pierwsze kroki w karierze IT: LinkedIn - wykorzystaj potencjał sieci
 
Tech 101: Scrum 25.04.19 Warszawa
Tech 101: Scrum 25.04.19 WarszawaTech 101: Scrum 25.04.19 Warszawa
Tech 101: Scrum 25.04.19 Warszawa
 
ARKit by Magdalena Pałka
ARKit by Magdalena PałkaARKit by Magdalena Pałka
ARKit by Magdalena Pałka
 
React Native by Artur Staszczyk
React Native by Artur StaszczykReact Native by Artur Staszczyk
React Native by Artur Staszczyk
 
Big Data - historia i przyszłość
Big Data - historia i przyszłośćBig Data - historia i przyszłość
Big Data - historia i przyszłość
 
Blockchain and Cryptocurrency Basics- #43 spotkanie WiT Kraków
Blockchain and Cryptocurrency Basics- #43 spotkanie WiT KrakówBlockchain and Cryptocurrency Basics- #43 spotkanie WiT Kraków
Blockchain and Cryptocurrency Basics- #43 spotkanie WiT Kraków
 
"Wyzwania automatyzacji w ciągłej integracji" - o tworzeniu i utrzymaniu test...
"Wyzwania automatyzacji w ciągłej integracji" - o tworzeniu i utrzymaniu test..."Wyzwania automatyzacji w ciągłej integracji" - o tworzeniu i utrzymaniu test...
"Wyzwania automatyzacji w ciągłej integracji" - o tworzeniu i utrzymaniu test...
 
Agnieszka Pocha - Od surowych danych do gotowego modelu - uczenie maszynowe w...
Agnieszka Pocha - Od surowych danych do gotowego modelu - uczenie maszynowe w...Agnieszka Pocha - Od surowych danych do gotowego modelu - uczenie maszynowe w...
Agnieszka Pocha - Od surowych danych do gotowego modelu - uczenie maszynowe w...
 
Monika Synoradzka - 10 sposobów na budowę silnego zespołu i bycie dobrym lide...
Monika Synoradzka - 10 sposobów na budowę silnego zespołu i bycie dobrym lide...Monika Synoradzka - 10 sposobów na budowę silnego zespołu i bycie dobrym lide...
Monika Synoradzka - 10 sposobów na budowę silnego zespołu i bycie dobrym lide...
 
Kulisy pracy w IT: Zawód Front- end Developer prezentacja Pawła Janasa
Kulisy pracy w IT: Zawód Front- end Developer prezentacja Pawła JanasaKulisy pracy w IT: Zawód Front- end Developer prezentacja Pawła Janasa
Kulisy pracy w IT: Zawód Front- end Developer prezentacja Pawła Janasa
 
Jak bardzo techniczny musi być tester?
Jak bardzo techniczny musi być tester?Jak bardzo techniczny musi być tester?
Jak bardzo techniczny musi być tester?
 
Poznaj GITa - Natalia Stanko
Poznaj GITa - Natalia StankoPoznaj GITa - Natalia Stanko
Poznaj GITa - Natalia Stanko
 
Poznaj GITa - część teoretyczna - Anna Szwiec
Poznaj GITa -  część teoretyczna - Anna SzwiecPoznaj GITa -  część teoretyczna - Anna Szwiec
Poznaj GITa - część teoretyczna - Anna Szwiec
 
HTML, CSS & Javascript Architecture (extended version) - Jan Kraus
HTML, CSS & Javascript Architecture (extended version) - Jan KrausHTML, CSS & Javascript Architecture (extended version) - Jan Kraus
HTML, CSS & Javascript Architecture (extended version) - Jan Kraus
 
Architektura html, css i javascript - Jan Kraus
Architektura html, css i javascript - Jan KrausArchitektura html, css i javascript - Jan Kraus
Architektura html, css i javascript - Jan Kraus
 
Hackerspace Wrocław
Hackerspace WrocławHackerspace Wrocław
Hackerspace Wrocław
 
Roman Czarko-Wasiutycz- Projektowanie baz danych
Roman Czarko-Wasiutycz- Projektowanie baz danychRoman Czarko-Wasiutycz- Projektowanie baz danych
Roman Czarko-Wasiutycz- Projektowanie baz danych
 
Justyna Hankiewicz- Jak zbudować efektywny zespół
Justyna Hankiewicz- Jak zbudować efektywny zespółJustyna Hankiewicz- Jak zbudować efektywny zespół
Justyna Hankiewicz- Jak zbudować efektywny zespół
 
Warsztaty o zdrowiu karolina jarosz trener personalny
Warsztaty o zdrowiu   karolina jarosz trener personalnyWarsztaty o zdrowiu   karolina jarosz trener personalny
Warsztaty o zdrowiu karolina jarosz trener personalny
 

Recently uploaded

Large Language Models and the End of Programming
Large Language Models and the End of ProgrammingLarge Language Models and the End of Programming
Large Language Models and the End of Programming
Matt Welsh
 
Explore Modern SharePoint Templates for 2024
Explore Modern SharePoint Templates for 2024Explore Modern SharePoint Templates for 2024
Explore Modern SharePoint Templates for 2024
Sharepoint Designs
 
OpenFOAM solver for Helmholtz equation, helmholtzFoam / helmholtzBubbleFoam
OpenFOAM solver for Helmholtz equation, helmholtzFoam / helmholtzBubbleFoamOpenFOAM solver for Helmholtz equation, helmholtzFoam / helmholtzBubbleFoam
OpenFOAM solver for Helmholtz equation, helmholtzFoam / helmholtzBubbleFoam
takuyayamamoto1800
 
Globus Compute wth IRI Workflows - GlobusWorld 2024
Globus Compute wth IRI Workflows - GlobusWorld 2024Globus Compute wth IRI Workflows - GlobusWorld 2024
Globus Compute wth IRI Workflows - GlobusWorld 2024
Globus
 
Exploring Innovations in Data Repository Solutions - Insights from the U.S. G...
Exploring Innovations in Data Repository Solutions - Insights from the U.S. G...Exploring Innovations in Data Repository Solutions - Insights from the U.S. G...
Exploring Innovations in Data Repository Solutions - Insights from the U.S. G...
Globus
 
Understanding Globus Data Transfers with NetSage
Understanding Globus Data Transfers with NetSageUnderstanding Globus Data Transfers with NetSage
Understanding Globus Data Transfers with NetSage
Globus
 
Paketo Buildpacks : la meilleure façon de construire des images OCI? DevopsDa...
Paketo Buildpacks : la meilleure façon de construire des images OCI? DevopsDa...Paketo Buildpacks : la meilleure façon de construire des images OCI? DevopsDa...
Paketo Buildpacks : la meilleure façon de construire des images OCI? DevopsDa...
Anthony Dahanne
 
Multiple Your Crypto Portfolio with the Innovative Features of Advanced Crypt...
Multiple Your Crypto Portfolio with the Innovative Features of Advanced Crypt...Multiple Your Crypto Portfolio with the Innovative Features of Advanced Crypt...
Multiple Your Crypto Portfolio with the Innovative Features of Advanced Crypt...
Hivelance Technology
 
Providing Globus Services to Users of JASMIN for Environmental Data Analysis
Providing Globus Services to Users of JASMIN for Environmental Data AnalysisProviding Globus Services to Users of JASMIN for Environmental Data Analysis
Providing Globus Services to Users of JASMIN for Environmental Data Analysis
Globus
 
Webinar: Salesforce Document Management 2.0 - Smarter, Faster, Better
Webinar: Salesforce Document Management 2.0 - Smarter, Faster, BetterWebinar: Salesforce Document Management 2.0 - Smarter, Faster, Better
Webinar: Salesforce Document Management 2.0 - Smarter, Faster, Better
XfilesPro
 
Globus Compute Introduction - GlobusWorld 2024
Globus Compute Introduction - GlobusWorld 2024Globus Compute Introduction - GlobusWorld 2024
Globus Compute Introduction - GlobusWorld 2024
Globus
 
Why React Native as a Strategic Advantage for Startup Innovation.pdf
Why React Native as a Strategic Advantage for Startup Innovation.pdfWhy React Native as a Strategic Advantage for Startup Innovation.pdf
Why React Native as a Strategic Advantage for Startup Innovation.pdf
ayushiqss
 
Vitthal Shirke Microservices Resume Montevideo
Vitthal Shirke Microservices Resume MontevideoVitthal Shirke Microservices Resume Montevideo
Vitthal Shirke Microservices Resume Montevideo
Vitthal Shirke
 
GlobusWorld 2024 Opening Keynote session
GlobusWorld 2024 Opening Keynote sessionGlobusWorld 2024 Opening Keynote session
GlobusWorld 2024 Opening Keynote session
Globus
 
How to Position Your Globus Data Portal for Success Ten Good Practices
How to Position Your Globus Data Portal for Success Ten Good PracticesHow to Position Your Globus Data Portal for Success Ten Good Practices
How to Position Your Globus Data Portal for Success Ten Good Practices
Globus
 
Globus Connect Server Deep Dive - GlobusWorld 2024
Globus Connect Server Deep Dive - GlobusWorld 2024Globus Connect Server Deep Dive - GlobusWorld 2024
Globus Connect Server Deep Dive - GlobusWorld 2024
Globus
 
Cracking the code review at SpringIO 2024
Cracking the code review at SpringIO 2024Cracking the code review at SpringIO 2024
Cracking the code review at SpringIO 2024
Paco van Beckhoven
 
Cyaniclab : Software Development Agency Portfolio.pdf
Cyaniclab : Software Development Agency Portfolio.pdfCyaniclab : Software Development Agency Portfolio.pdf
Cyaniclab : Software Development Agency Portfolio.pdf
Cyanic lab
 
Enhancing Research Orchestration Capabilities at ORNL.pdf
Enhancing Research Orchestration Capabilities at ORNL.pdfEnhancing Research Orchestration Capabilities at ORNL.pdf
Enhancing Research Orchestration Capabilities at ORNL.pdf
Globus
 
In 2015, I used to write extensions for Joomla, WordPress, phpBB3, etc and I ...
In 2015, I used to write extensions for Joomla, WordPress, phpBB3, etc and I ...In 2015, I used to write extensions for Joomla, WordPress, phpBB3, etc and I ...
In 2015, I used to write extensions for Joomla, WordPress, phpBB3, etc and I ...
Juraj Vysvader
 

Recently uploaded (20)

Large Language Models and the End of Programming
Large Language Models and the End of ProgrammingLarge Language Models and the End of Programming
Large Language Models and the End of Programming
 
Explore Modern SharePoint Templates for 2024
Explore Modern SharePoint Templates for 2024Explore Modern SharePoint Templates for 2024
Explore Modern SharePoint Templates for 2024
 
OpenFOAM solver for Helmholtz equation, helmholtzFoam / helmholtzBubbleFoam
OpenFOAM solver for Helmholtz equation, helmholtzFoam / helmholtzBubbleFoamOpenFOAM solver for Helmholtz equation, helmholtzFoam / helmholtzBubbleFoam
OpenFOAM solver for Helmholtz equation, helmholtzFoam / helmholtzBubbleFoam
 
Globus Compute wth IRI Workflows - GlobusWorld 2024
Globus Compute wth IRI Workflows - GlobusWorld 2024Globus Compute wth IRI Workflows - GlobusWorld 2024
Globus Compute wth IRI Workflows - GlobusWorld 2024
 
Exploring Innovations in Data Repository Solutions - Insights from the U.S. G...
Exploring Innovations in Data Repository Solutions - Insights from the U.S. G...Exploring Innovations in Data Repository Solutions - Insights from the U.S. G...
Exploring Innovations in Data Repository Solutions - Insights from the U.S. G...
 
Understanding Globus Data Transfers with NetSage
Understanding Globus Data Transfers with NetSageUnderstanding Globus Data Transfers with NetSage
Understanding Globus Data Transfers with NetSage
 
Paketo Buildpacks : la meilleure façon de construire des images OCI? DevopsDa...
Paketo Buildpacks : la meilleure façon de construire des images OCI? DevopsDa...Paketo Buildpacks : la meilleure façon de construire des images OCI? DevopsDa...
Paketo Buildpacks : la meilleure façon de construire des images OCI? DevopsDa...
 
Multiple Your Crypto Portfolio with the Innovative Features of Advanced Crypt...
Multiple Your Crypto Portfolio with the Innovative Features of Advanced Crypt...Multiple Your Crypto Portfolio with the Innovative Features of Advanced Crypt...
Multiple Your Crypto Portfolio with the Innovative Features of Advanced Crypt...
 
Providing Globus Services to Users of JASMIN for Environmental Data Analysis
Providing Globus Services to Users of JASMIN for Environmental Data AnalysisProviding Globus Services to Users of JASMIN for Environmental Data Analysis
Providing Globus Services to Users of JASMIN for Environmental Data Analysis
 
Webinar: Salesforce Document Management 2.0 - Smarter, Faster, Better
Webinar: Salesforce Document Management 2.0 - Smarter, Faster, BetterWebinar: Salesforce Document Management 2.0 - Smarter, Faster, Better
Webinar: Salesforce Document Management 2.0 - Smarter, Faster, Better
 
Globus Compute Introduction - GlobusWorld 2024
Globus Compute Introduction - GlobusWorld 2024Globus Compute Introduction - GlobusWorld 2024
Globus Compute Introduction - GlobusWorld 2024
 
Why React Native as a Strategic Advantage for Startup Innovation.pdf
Why React Native as a Strategic Advantage for Startup Innovation.pdfWhy React Native as a Strategic Advantage for Startup Innovation.pdf
Why React Native as a Strategic Advantage for Startup Innovation.pdf
 
Vitthal Shirke Microservices Resume Montevideo
Vitthal Shirke Microservices Resume MontevideoVitthal Shirke Microservices Resume Montevideo
Vitthal Shirke Microservices Resume Montevideo
 
GlobusWorld 2024 Opening Keynote session
GlobusWorld 2024 Opening Keynote sessionGlobusWorld 2024 Opening Keynote session
GlobusWorld 2024 Opening Keynote session
 
How to Position Your Globus Data Portal for Success Ten Good Practices
How to Position Your Globus Data Portal for Success Ten Good PracticesHow to Position Your Globus Data Portal for Success Ten Good Practices
How to Position Your Globus Data Portal for Success Ten Good Practices
 
Globus Connect Server Deep Dive - GlobusWorld 2024
Globus Connect Server Deep Dive - GlobusWorld 2024Globus Connect Server Deep Dive - GlobusWorld 2024
Globus Connect Server Deep Dive - GlobusWorld 2024
 
Cracking the code review at SpringIO 2024
Cracking the code review at SpringIO 2024Cracking the code review at SpringIO 2024
Cracking the code review at SpringIO 2024
 
Cyaniclab : Software Development Agency Portfolio.pdf
Cyaniclab : Software Development Agency Portfolio.pdfCyaniclab : Software Development Agency Portfolio.pdf
Cyaniclab : Software Development Agency Portfolio.pdf
 
Enhancing Research Orchestration Capabilities at ORNL.pdf
Enhancing Research Orchestration Capabilities at ORNL.pdfEnhancing Research Orchestration Capabilities at ORNL.pdf
Enhancing Research Orchestration Capabilities at ORNL.pdf
 
In 2015, I used to write extensions for Joomla, WordPress, phpBB3, etc and I ...
In 2015, I used to write extensions for Joomla, WordPress, phpBB3, etc and I ...In 2015, I used to write extensions for Joomla, WordPress, phpBB3, etc and I ...
In 2015, I used to write extensions for Joomla, WordPress, phpBB3, etc and I ...
 

Architecure components by Paulina Szklarska

  • 2. Hello! Nice to meet you Paulina Szklarska • Android Developer • co-organizer of Toast Wrocław meetups • cat owner/travel enthusiast @pszklarska @pszklarska @p_szklarska
  • 5. “ Why there is no official architecture guide in Android documentation? ~ me, some time ago
  • 6. Before May 2017 https://plus.google.com/+DianneHackborn/posts/FXCCYxepsDU „Should you use MVC? Or MVP? Or MVVM? I have no idea. Heck, I only know about MVC from school and had to do a Google search to find other options to put here.” ~ Dianne Hackborn, Android Framework Engineer, May 2016
  • 7.
  • 8. ARCHITECTURE COMPONENTS ROOM LIFECYCLE COMPONENTS VIEW MODEL LIVE DATA PAGING LIBRARY
  • 10. Room Entity Single database table DAO Defines methods to access database Database Holds entities and DAOs
  • 11. 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
  • 14. public class Cat {
 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
  • 15. @Entity
 public class Cat {
 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
  • 16. @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
  • 17. @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
  • 18. @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
  • 19. @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
  • 20. public interface CatDao {
 
 }a
  • 22. @Dao
 public interface CatDao {
 
 @Insert
 void insert(Cat... cats);
 
 @Update
 void update(Cat... cats);
 
 @Delete
 void delete(Cat... cats);
 }a
  • 23. @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
  • 24. @Dao
 public interface CatDao {
 
 @Insert
 void insert(Cat... cats);
 
 }a
  • 25. @Dao
 public interface CatDao {
 
 @Insert
 void insert(Cat... cats);
 
 @Insert
 void insert(Cat cat);
 
 }a
  • 26. @Dao
 public interface CatDao {
 
 @Insert
 void insert(Cat... cats);
 
 @Insert
 void insert(Cat cat);
 
 @Insert
 void insert(List<Cat> catList);
 
 }a
  • 27. @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
  • 28. @Dao
 public interface CatDao {
 
 @Query("SELECT * FROM kittens")
 List<Cat> getAllCats();
 }a
  • 29. @Dao
 public interface CatDao {
 
 @Query("SELECT * FROM kittens")
 List<Cat> getAllCats();
 
 @Query("SELECT * FROM kittens WHERE id=:id")
 Cat getCatById(int id);
 
 }a
  • 30. @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();
 
 }a
  • 31. @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
  • 33. @Database(entities = { Cat.class }, version = 1)
 public class CatDatabase {
 
 }a
  • 34. @Database(entities = { Cat.class }, version = 1)
 public abstract class CatDatabase extends RoomDatabase {
 
 }a
  • 35. @Database(entities = { Cat.class }, version = 1)
 public abstract class CatDatabase extends RoomDatabase {
 
 public abstract CatDao getCatDao();
 }a
  • 36. @Database(entities = { Cat.class }, version = 1)
 public abstract class CatDatabase extends RoomDatabase {
 
 private static CatDatabase create(final Context context) {
 return Room.databaseBuilder( context, CatDatabase.class, "catsDatabase.db")
 .build();
 } 
 
 public abstract CatDao getCatDao();
 }a
  • 37. CatDatabase
 .getInstance(context)
 .getCatDao()
 .insert(new Cat(1, 
 "Muffin", 
 "/muffin.jpg")); List<Cat> allCats = CatDatabase
 .getInstance(context)
 .getCatDao()
 .getAllCats();
  • 40. @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
  • 41. @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
  • 42. @Entity(foreignKeys = @ForeignKey(entity = Owner.class))
 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
  • 43. @Entity(foreignKeys = @ForeignKey(entity = Owner.class,
 parentColumns = "id"))
 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
  • 44. @Entity(foreignKeys = @ForeignKey(entity = Owner.class,
 parentColumns = "id",
 childColumns = "ownerId"))
 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
  • 45. @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
  • 46. @Dao
 public interface CatDao {
 
 @Query("SELECT * FROM kittens WHERE ownerId=:ownerId")
 List<Cat> findCatsForOwner(int ownerId);
 
 }a

  • 48. @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
  • 49. @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
  • 50. public class OwnerWithCats {
 @Embedded public Owner owner;
 
 @Relation(parentColumn = "id",
 entityColumn = "ownerId") public List<Cat> catList;
 }a
  • 51. @Dao
 public interface OwnerWithCatsDao {
 
 @Query("SELECT * FROM owner")
 public List<OwnerWithCats> getOwnersWithCats();
 
 }a
  • 53. @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
  • 54. public class DateConverter {
 
 @TypeConverter public LocalDate toDate(long dateLong) { return LocalDate.ofEpochDay(dateLong); } @TypeConverter public long fromDate(LocalDate date) { return date.toEpochDay(); }
 }
  • 55. @Database(entities = { Cat.class }, version = 1)
 public abstract class CatDatabase extends RoomDatabase {
 
 }a
  • 56. @Database(entities = { Cat.class }, version = 1)
 @TypeConverters(DateConverter.class)
 public abstract class CatDatabase extends RoomDatabase {
 
 }a
  • 58. @Entity
 public class Cat {
 @PrimaryKey public int id;
 public String name;
 public String url;
 }a
  • 59. @Entity
 public class Cat {
 @PrimaryKey public int id;
 public String name;
 public String url;
 public String age;
 }a
  • 60. 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.
  • 61. @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
  • 62. @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
  • 63. 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.
  • 64. @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
  • 65. @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
  • 66. @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
  • 67. 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");
 }
 };
 }
  • 68. android { javaCompileOptions {
 annotationProcessorOptions {
 arguments = ["room.schemaLocation":
 "$projectDir/schemas".toString()]
 }
 }
 } }
  • 69. 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
 }, . . . ]
  • 70. @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
  • 71. @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
  • 72. @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
  • 74. @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();
 }a @After
 public void closeDb() throws IOException {
 database.close();
 }a
 }a
  • 75. @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();
 }a
 
 @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();
 }a
 }a
  • 76. tl;dr • 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
  • 81. 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());
 }

  • 82. public class LocationManager {
 
 public LocationManager() {
 // do something
 }a
 
 void addLocationListener() {
 // register location manager listener
 }a 
 void removeLocationListener() {
 // remove location manager listener
 }a
 }a
  • 83. public class LocationManager implements LifecycleObserver {
 
 public LocationManager() { // do something 
 }a
 
 void addLocationListener() {
 // register location manager listener
 }a
 
 void removeLocationListener() {
 // remove location manager listener
 }a
 }a
  • 84. public class LocationManager implements LifecycleObserver {
 
 public LocationManager(LifecycleOwner lifecycleOwner) { // do something 
 lifecycleOwner.getLifecycle().addObserver(this);
 }a
 
 void addLocationListener() {
 // register location manager listener
 }a
 
 void removeLocationListener() {
 // remove location manager listener
 }a
 }a
  • 85. 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
 
 void removeLocationListener() {
 // remove location manager listener
 }a
 }a
  • 86. 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
  • 87. 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());
 }

  • 88. 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
  • 89. 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
  • 90. public class GithubApplication extends Application { @Override public void onCreate() { super.onCreate(); ProcessLifecycleOwner.get() .getLifecycle() .addObserver(new AppLifecycleObserver()); } }
  • 91. 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 } }
  • 94. 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
  • 95. 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
 }
 }
  • 96. 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
 }
 }
  • 97. public class UsersActivity extends AppCompatActivity {
 
 @Override
 protected void onCreate(final Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 setContentView(R.layout.activity_main); 
 }a
 }a
  • 98. 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);
 
 }a
 }a
  • 99. 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
  • 102. LiveData<List<User>> observes notifies only if activity is at least started List<User>
  • 103. public class UsersViewModel extends ViewModel {
 
 private List<User> userList;
 
 public List<User> getUserList() {
 if (userList == null) {
 usersList = loadUsers();
 }a
 return userList;
 }a
 
 private List<User> loadUsers() {
 // do something to load users
 }a
 }a
  • 104. 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
  • 105. public class UsersViewModel extends ViewModel {
 
 private MutableLiveData<List<User>> userList = new MutableLiveData<>();
 
 public LiveData<List<User>> getUserList() {
 return userList;
 }a
 }a
  • 106. 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
  • 107. 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
  • 108. 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
  • 109. tl;dr • keeps your UI always updated (follows observer pattern) • no memory leaks (data bound with lifecycle) • no data sent to stopped activity
  • 110. @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

  • 111. 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