Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Android Architecture Components

Android Architecture Components

Slides da minha apresentação sobre Android Architecture Components na Android Dev Conference 2017.

Danilo Prado

August 25, 2017
Tweet

Other Decks in Programming

Transcript

  1. Por quê? • Ciclo de vida complexo. • Boilerplate code.

    • Ausência de uma arquitetura recomendada pela Google.
  2. Como? • Lifecycle: Simplifique o gerenciamento de ciclos de vida

    no seu app. • Room: Evite boilerplate com um ORM simples e eficiente. • LiveData: Observe dados respeitando os ciclos de vida. • ViewModel: Armazene e gerencie os dados da UI e garanta que eles sobreviverão às mudanças de configuração.
  3. The old way • Seus componentes externos não sabiam sobre

    o ciclo de vida dos UI Controllers (Fragments/ AcTviTes). • Métodos onStart(), onStop() etc. podem ficar bem grandes. • Ausência de um método para saber o estado atual do ciclo de vida do UI Controller.
  4. public void onCreate(...) { myLocationListener = new MyLocationListener(this, (location) ->

    { // update UI }); } public void onStart() { super.onStart(); myLocationListener.start(); } public void onStop() { super.onStop(); myLocationListener.stop(); } The old way
  5. The new way • Qualquer componente pode observar o ciclo

    de vida de um LifecycleOwner. • Métodos onStart(), onStop() etc. menores. • É possível consultar o estado atual do ciclo de vida de um LifecycleOwner.
  6. LifecycleOwner class MyActivity extends LifecycleActivity { private MyLocationListener myLocationListener; public

    void onCreate(...) { myLocationListener = new MyLocationListener(getLifecycle(), ...) // update UI }); } }
  7. LifecycleObserver class MyLocationListener implements LifecycleObserver { public MyLocationListener(Lifecycle lifecycle, ...)

    { lifecycle.addObserver(this); } @OnLifecycleEvent(Lifecycle.Event.ON_START) void start() { // connect } @OnLifecycleEvent(Lifecycle.Event.ON_STOP) void stop() { // disconnect if connected } }
  8. The old way (SQLite) • Criar uma classe herdada de

    SQLiteHelper. • Criar queries para criar cada uma das tabelas. • Criar queries para ler/armazenar dados. • Processar os resultados uTlizando cursores. • Apresentar os dados uTlizando loaders.
  9. The new way (Room) • Criar uma classe de Database.

    • Anotar os modelos para que se tornem EnTdades. • Criar os DAOs para acessar os dados.
  10. Criando a classe Database @Database(entities = {Task.class}, version = 1)

    public abstract class AppDatabase extends RoomDatabase { private static AppDatabase instance; public static AppDatabase getInstance(Context context) { if (instance == null) { instance = Room.databaseBuilder(context, AppDatabase.class, “tasklist.db").build(); } return instance; } public abstract TaskDao taskDao(); }
  11. Criando a classe Database @Database(entities = {Task.class}, version = 1)

    public abstract class AppDatabase extends RoomDatabase { private static AppDatabase instance; public static AppDatabase getInstance(Context context) { if (instance == null) { instance = Room.databaseBuilder(context, AppDatabase.class, “tasklist.db").build(); } return instance; } public abstract TaskDao taskDao(); }
  12. Criando a classe Database @Database(entities = {Task.class}, version = 1)

    public abstract class AppDatabase extends RoomDatabase { private static AppDatabase instance; public static AppDatabase getInstance(Context context) { if (instance == null) { instance = Room.databaseBuilder(context, AppDatabase.class, “tasklist.db").build(); } return instance; } public abstract TaskDao taskDao(); }
  13. Criando a classe Database @Database(entities = {Task.class}, version = 1)

    public abstract class AppDatabase extends RoomDatabase { private static AppDatabase instance; public static AppDatabase getInstance(Context context) { if (instance == null) { instance = Room.databaseBuilder(context, AppDatabase.class, “tasklist.db").build(); } return instance; } public abstract TaskDao taskDao(); }
  14. Criando a classe Database @Database(entities = {Task.class}, version = 1)

    public abstract class AppDatabase extends RoomDatabase { private static AppDatabase instance; public static AppDatabase getInstance(Context context) { if (instance == null) { instance = Room.databaseBuilder(context, AppDatabase.class, “tasklist.db").build(); } return instance; } public abstract TaskDao taskDao(); }
  15. Criando uma enGdade public class Task { private int id;

    private String title; private String description; //Getters e setters omitidos, mas são necessários! }
  16. Criando uma enGdade @Entity public class Task { private int

    id; private String title; private String description; //Getters e setters omitidos, mas são necessários! }
  17. Criando uma enGdade @Entity public class Task { @PrimaryKey(autoGenerate =

    true) private int id; private String title; private String description; //Getters e setters omitidos, mas são necessários! }
  18. Criando um DAO @Dao public interface TaskDao { @Query("SELECT *

    FROM task") List<Task> getAll(); @Insert(onConflict = REPLACE) void insert(Task task); }
  19. Criando um DAO @Dao public interface TaskDao { @Query("SELECT *

    FROM task") List<Task> getAll(); @Insert(onConflict = REPLACE) void insert(Task task); @Update void update(Task... tasks); }
  20. Criando um DAO @Dao public interface TaskDao { @Query("SELECT *

    FROM task") List<Task> getAll(); @Insert(onConflict = REPLACE) void insert(Task task); @Update void update(Task... tasks); @Delete void delete(Task... tasks); }
  21. Verificação do SQL em tempo de compilação Error:(17, 26) error:

    There is a problem with the query: [SQLITE_ERROR] SQL error or missing database (no such table: tsk)
  22. Verificação do SQL em tempo de compilação Error:(17, 28) error:

    Not sure how to convert a Cursor to this method's return type. Warning:(17, 28) The query returns some columns [id, title, description] which are not use by java.lang.Double.
  23. The old way • Chamadas manuais após mudanças no Model.

    • O gerenciamento de Observers baseado no ciclo de vida era feito manualmente.
  24. The new way • O UI Controller é automaTcamente noTficado

    de mudanças no Model. • Gerenciamento de Observers automáTco de acordo com o Lifecycle atual do UI Controller.
  25. LiveData public class LocationLiveData extends LiveData<Location> { private LocationManager locationManager;

    private SimpleLocationListener listener = new SimpleLocationListener() { @Override public void onLocationChanged(Location location) { setValue(location); } }; public LocationLiveData(Context context) { locationManager = (LocationManager) context.getSystemService( Context.LOCATION_SERVICE); } ... }
  26. LiveData public class LocationLiveData extends LiveData<Location> { private LocationManager locationManager;

    private SimpleLocationListener listener = new SimpleLocationListener() { @Override public void onLocationChanged(Location location) { setValue(location); } }; public LocationLiveData(Context context) { locationManager = (LocationManager) context.getSystemService( Context.LOCATION_SERVICE); } ... }
  27. LiveData public class LocationLiveData extends LiveData<Location> { private LocationManager locationManager;

    private SimpleLocationListener listener = new SimpleLocationListener() { @Override public void onLocationChanged(Location location) { setValue(location); } }; public LocationLiveData(Context context) { locationManager = (LocationManager) context.getSystemService( Context.LOCATION_SERVICE); } ... }
  28. LiveData public class LocationLiveData extends LiveData<Location> { ... @Override protected

    void onActive() { locationManager.requestLocationUpdates(…, listener); } @Override protected void onInactive() { locationManager.removeUpdates(listener); } }
  29. TransformaGons if (tasks.getValue().isEmpty()) { tasks = Transformations.map(tasks, taskList -> {

    taskList.add(new Task("Welcome", "Sample task")); return taskList; }); }
  30. The old way • Lógica nos UI Controllers (god acTviTes).

    • Perda dos dados nas mudanças de orientação.
  31. The new way • Lógica isolada no ViewModel. • O

    ViewModel não é destruído nas mudanças de orientação.
  32. ViewModel class TaskViewModel extends AndroidViewModel { private LiveData<List<Task>> tasks; private

    AppDatabase db; public TaskViewModel(Application application) { super(application); db = AppDatabase .getInstance(this.getApplication().getApplicationContext()); tasks = db.taskDao().getAll(); } LiveData<List<Task>> getTasks() { return tasks; } }
  33. ViewModel class TaskViewModel extends AndroidViewModel { private LiveData<List<Task>> tasks; private

    AppDatabase db; public TaskViewModel(Application application) { super(application); db = AppDatabase .getInstance(this.getApplication().getApplicationContext()); tasks = db.taskDao().getAll(); } LiveData<List<Task>> getTasks() { return tasks; } }
  34. ViewModel class TaskViewModel extends AndroidViewModel { private LiveData<List<Task>> tasks; private

    AppDatabase db; public TaskViewModel(Application application) { super(application); db = AppDatabase .getInstance(this.getApplication().getApplicationContext()); tasks = db.taskDao().getAll(); } LiveData<List<Task>> getTasks() { return tasks; } }
  35. ViewModel class TaskViewModel extends AndroidViewModel { private LiveData<List<Task>> tasks; private

    AppDatabase db; public TaskViewModel(Application application) { super(application); db = AppDatabase .getInstance(this.getApplication().getApplicationContext()); tasks = db.taskDao().getAll(); } LiveData<List<Task>> getTasks() { return tasks; } }
  36. ViewModel class TaskViewModel extends AndroidViewModel { private LiveData<List<Task>> tasks; private

    AppDatabase db; public TaskViewModel(Application application) { super(application); db = AppDatabase .getInstance(this.getApplication().getApplicationContext()); tasks = db.taskDao().getAll(); } LiveData<List<Task>> getTasks() { return tasks; } }
  37. ViewModel @Override protected void onCreate(Bundle savedInstanceState) { //Código omitido para

    melhor visualização taskViewModel = ViewModelProviders .of(this) .get(TaskViewModel.class); taskViewModel .getTasks() .observe(this, this::updateRecyclerView); } private void updateRecyclerView(List<Task> tasks) { //Código de refresh da RecyclerView }
  38. ViewModel @Override protected void onCreate(Bundle savedInstanceState) { //Código omitido para

    melhor visualização taskViewModel = ViewModelProviders .of(this) .get(TaskViewModel.class); taskViewModel .getTasks() .observe(this, this::updateRecyclerView); } private void updateRecyclerView(List<Task> tasks) { //Código de refresh da RecyclerView }