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

Android Architecture Components by Ihor Dzikovskyy

GDG Ternopil
December 02, 2017

Android Architecture Components by Ihor Dzikovskyy

Android Architecture Components by Ihor Dzikovskyy

GDG Ternopil

December 02, 2017
Tweet

More Decks by GDG Ternopil

Other Decks in Programming

Transcript

  1. Android Architecture Components A collection of libraries that help you

    design robust, testable, and maintainable apps. • Lifecycle-Aware Components • LiveData • ViewModel
  2. Lifecycle is an object that defines an Android Lifecycle LifecycleOwner

    is an interface for objects with a Lifecycle LifecycleObserver is as interface for observing a LifecycleOwner Lifecycle-Aware Components Fragments and Activities in Support Library 26.1.0 and later already implement the LifecycleOwner interface.
  3. Common implementation of lifecycle handling @Override public void onCreate(...) {

    myLocationListener = new MyLocationListener(this, (location) -> { // update UI }); } @Override public void onStart() { myLocationListener.start(); // manage other components that need to respond to the activity lifecycle } @Override public void onStop() { myLocationListener.stop(); // manage other components that need to respond to the activity lifecycle }
  4. Component can start before the activity is stopped class MyActivity

    extends AppCompatActivity { @Override public void onStart() { super.onStart(); Util.checkUserStatus(result -> { // what if this callback is invoked AFTER activity is stopped? if (result) { myLocationListener.start(); } }); }
  5. Lifecycle Defines an object that has an Android Lifecycle. Class

    that holds the information about the lifecycle state of a component (like an activity or a fragment) and allows other objects to observe this state.
  6. Lifecycle on location tracking example class MyActivity extends AppCompatActivity {

    private MyLocationListener myLocationListener; public void onCreate(...) { myLocationListener = new MyLocationListener(this, getLifecycle(), location -> { // update UI }); Util.checkUserStatus(result -> { if (result) { myLocationListener.enable(); } }); } }
  7. LifecycleObserver implementation class MyLocationListener implements LifecycleObserver { //Receive callbacks for

    Lifecycle events @OnLifecycleEvent(Lifecycle.Event.ON_START) void start() { if (enabled) { // connect } } public void enable() { enabled = true; //Query the current state of the Lifecycle if (lifecycle.getCurrentState().isAtLeast(STARTED)) { // connect if not connected } } @OnLifecycleEvent(Lifecycle.Event.ON_STOP) void stop() { // disconnect if connected } }
  8. DefaultLifecycleObserver and Java 8 class TestObserver implements DefaultLifecycleObserver { @Override

    public void onCreate(LifecycleOwner owner) { // your code } } public interface DefaultLifecycleObserver extends FullLifecycleObserver { //provides default implementation for all 6 FullLifecycleObserver methods @Override default void onCreate(@NonNull LifecycleOwner owner) { } } If you use Java 8 language, always prefer it over annotations.
  9. Implementing a custom LifecycleOwner public class MyActivity extends Activity implements

    LifecycleOwner { private LifecycleRegistry mLifecycleRegistry; @Override protected void onCreate(Bundle savedInstanceState) { mLifecycleRegistry = new LifecycleRegistry(this); mLifecycleRegistry.markState(Lifecycle.State.CREATED); } @Override public void onStart() { mLifecycleRegistry.markState(Lifecycle.State.STARTED); } @Override public Lifecycle getLifecycle() { return mLifecycleRegistry; } }
  10. LiveData • Observable data holder class • Is lifecycle-aware •

    Only notifies active observers about updates • The Room persistence library supports observable queries, which return LiveData objects Observer • A simple callback that can receive from LiveData
  11. Work with LiveData • Create an instance of LiveData to

    hold a certain type of data. This is usually done within your ViewModel class • Create an Observer object that defines the onChanged() method (usually done in a UI controller, such as an activity or fragment) • Attach the Observer object to the LiveData object using the observe() method. The observe() method takes a LifecycleOwner object
  12. Create LiveData objects public class NameViewModel extends ViewModel { //

    Create a LiveData with a String private MutableLiveData<String> mCurrentName; public MutableLiveData<String> getCurrentName() { if (mCurrentName == null) { mCurrentName = new MutableLiveData<String>(); } return mCurrentName; } // Rest of the ViewModel... }
  13. Observe LiveData objects // Get the ViewModel viewModel = ViewModelProviders.of(this).get(NameViewModel.class);

    // Create the observer which updates the UI final Observer<String> nameObserver = new Observer<String>() { @Override public void onChanged(@Nullable final String newName) { // Update the UI, in this case, a TextView nameTextView.setText(newName); } }; // Observe the LiveData, passing in this activity as the LifecycleOwner and the observer viewModel.getCurrentName().observe(this, nameObserver);
  14. Update LiveData objects button.setOnClickListener(new OnClickListener() { @Override public void onClick(View

    v) { String anotherName = "John Doe"; viewModel.getCurrentName().setValue(anotherName); } }); liveData.postValue("a"); //call it from a worker thread liveData.setValue("b"); //call it from a main thread
  15. Transforming LiveData • map() - apply function to change LiveData

    output • switchMap() - apply function that swaps LiveData observer it is listening to • MediatorLiveData - LiveData with multiple sources for custom transformations
  16. Transformations.map(...) Transformations.map() applies a function on a LiveData instance and

    dispatches the result to its observers, giving you the opportunity to manipulate the data value. LiveData<User> userLiveData = ...; LiveData<String> userName = Transformations.map(userLiveData, user -> { user.name + " " + user.lastName });
  17. Transformations.switchMap(...) Transformations.switchMap() applies a function to the value stored in

    the LiveData object. The function passed to switchMap() must return a LiveData object MutableLiveData<String> userIdLiveData = ...; LiveData<User> userLiveData = Transformations.switchMap(userIdLiveData, id -> repository.getUserById(id)); void setUserId(String userId) { this.userIdLiveData.setValue(userId); }
  18. ViewModel • Designed to hold data that is related to

    the UI • Allows data to survive configuration changes such as screen rotations • ViewModel objects are scoped to the Lifecycle
  19. Implement a ViewModel public class MyViewModel extends ViewModel { private

    MutableLiveData<List<User>> users; public LiveData<List<User>> getUsers() { if (users == null) { users = new MutableLiveData<List<Users>>(); loadUsers(); } return users; } private void loadUsers() { // Do an asyncronous operation to fetch users } }
  20. ViewModelProviders public class MyActivity extends AppCompatActivity { public void onCreate(Bundle

    savedInstanceState) { // Create a ViewModel the first time the system calls an activity's onCreate() method. // Re-created activities receive the same MyViewModel instance created by the first activity. MyViewModel viewModel = ViewModelProviders.of(this).get(MyViewModel.class); viewModel.getUsers().observe(this, users -> { // update UI }); } }
  21. AndroidViewModel Caution: A ViewModel must never reference a View, Lifecycle,

    or any class that may hold a reference to the activity context. AndroidViewModel is Application context aware ViewModel AndroidViewModel subclasses must have a constructor which accepts Application as the only parameter.
  22. The lifecycle of a ViewModel ViewModel objects are scoped to

    the Lifecycle passed to the ViewModelProvider when getting the ViewModel.
  23. Share data between fragments public class SharedViewModel extends ViewModel {

    private final MutableLiveData<Item> selected = new MutableLiveData<Item>(); public void select(Item item) { selected.setValue(item); } public LiveData<Item> getSelected() { return selected; } } //Fragments can share a ViewModel using their activity scope SharedViewModel viewModel = ViewModelProviders.of(getActivity()).get(SharedViewModel.class);