Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Architecture components, Константин Марс, TeamLead, Senior Developer, DataArt

140 views

Published on

Architecture components

Published in: Education
  • Be the first to comment

Architecture components, Константин Марс, TeamLead, Senior Developer, DataArt

  1. 1. Architecture Components Build your app right way and enjoy IT! :) Constantine Mars Team Lead, Senior Developer @ DataArt
  2. 2. #gdg_kharkiv_center Android Has “Good Bones” Components: -Activities -Fragments -Services -Content Providers -Broadcast Receivers
  3. 3. #gdg_kharkiv_center But… There are Everyday Problems to Solve App-hopping OS may kill app at random time App components lifecycle is not under control Components should not depend on each other Can’t rely on data, stored in components
  4. 4. #gdg_kharkiv_center Simply related to Activity Lifecycle
  5. 5. #gdg_kharkiv_center Common Principles for staying in the mind :) -Separation of concerns -Provide solid user experience -Keep UI lean and simple -Keep UI free of app logic -Drive UI from model -Use persistent model -Assign clear responsibilities for each model class
  6. 6. #gdg_kharkiv_center Focus on Separation of Concerns... image from fernandocejas.com
  7. 7. #gdg_kharkiv_center Consider Clean Architecture approach... image from fernandocejas.com
  8. 8. #gdg_kharkiv_center Remember Good Architecture Goals... -Modular app -Each class responsible for one well-defined function -Should be no god objects -The app should be testable
  9. 9. #gdg_kharkiv_center And Finally - Android Recommended Architecture
  10. 10. #gdg_kharkiv_center Android Recommended Architecture. Another View image from Guide to App Architecture
  11. 11. #gdg_kharkiv_center Be together. not the same
  12. 12. #gdg_kharkiv_center Be together. not the same “It is impossible to have one way of writing apps that will be the best for every scenario. That being said, this recommended architecture should be a good starting point for most use cases. If you already have a good way of writing Android apps, you don't need to change.” Quote from Guide to App Architecture
  13. 13. Architecture Components Building blocks
  14. 14. #gdg_kharkiv_center Views = UI Controllers = LifecycleOwners Purpose: Display data and pass on UI events Neither contain the UI data, nor directly manipulate data Examples: Activity, Fragment
  15. 15. #gdg_kharkiv_center LifecycleActivity, LifecycleFragment After the lifecycles API in the Architecture Components becomes stable, the Fragment class in the Android Support Library will implement LifecycleOwner
  16. 16. #gdg_kharkiv_center ViewModel Data holder for Activity/Fragment Survives configuration changes NEVER references View / Activity / Fragment
  17. 17. #gdg_kharkiv_center public class DetailActivityViewModel extends ViewModel { private WeatherEntry mWeather; public DetailActivityViewModel() {} public WeatherEntry getWeather() { return mWeather; } public void setWeather(WeatherEntry weatherEntry) { mWeather = weatherEntry; } } ViewModel extend ViewModel
  18. 18. #gdg_kharkiv_center ViewModel and Lifecycle
  19. 19. #gdg_kharkiv_center public class DetailActivity extends LifecycleActivity { DetailActivityViewModel viewModel; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); ... viewModel = ViewModelProviders.of(this).get(DetailActivityViewModel.class); } ... ViewModel and LifecycleOwner Provider
  20. 20. #gdg_kharkiv_center LiveData Represent data needed for the UI to display An observable data holder Lifecycle aware Automatic subscription management
  21. 21. #gdg_kharkiv_center LiveData event propagation
  22. 22. #gdg_kharkiv_center LiveData sample implementation
  23. 23. #gdg_kharkiv_center public class DetailActivityViewModel extends ViewModel { private MutableLiveData<WeatherEntry> mWeather; public DetailActivityViewModel() {} public MutableLiveData<WeatherEntry> getWeather() { return mWeather; } public void setWeather(WeatherEntry weatherEntry) { mWeather.postValue(weatherEntry); } } Live Data LiveData
  24. 24. #gdg_kharkiv_center public class DetailActivity extends LifecycleActivity { DetailActivityViewModel viewModel; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); ... viewModel = ViewModelProviders.of(this).get(DetailActivityViewModel.class); viewModel.getWeather().observe(this, weatherEntry -> { if(weatherEntry!=null) { bindWeatherToUI(weatherEntry); } }); } Live Data observing Observe
  25. 25. #gdg_kharkiv_center Repository -Single source of truth -ViewModels simply request data from the repository -Is a mediator between the different data sources image from fernandocejas.com
  26. 26. #gdg_kharkiv_center Remote Network Data Source Manages data from a remote data source, such as the internet May use REST, Cloud
  27. 27. #gdg_kharkiv_center Model Manages local data stored in the database
  28. 28. #gdg_kharkiv_center Layered architecture pattern Each class in the diagram only stores a reference to the class or classes directly "below it" and not any classes above it
  29. 29. Room ORooM :)
  30. 30. #gdg_kharkiv_center Room?
  31. 31. #gdg_kharkiv_center Room ORM purposes -Less boilerplate compared to the built-in APIs -Compile-time validation of SQL queries -Data observation via LiveData, RxJava
  32. 32. #gdg_kharkiv_center Room annotations -@Entity -@Dao -@Database
  33. 33. #gdg_kharkiv_center @Entity
  34. 34. #gdg_kharkiv_center @Entity(tableName = "weather", indices = {@Index(value = {"date"}, unique = true)}) public class WeatherEntry { @PrimaryKey(autoGenerate = true) private int id; … } @Entity declaration
  35. 35. #gdg_kharkiv_center //Room constructor public WeatherEntry(int id, int weatherIconId, Date date, ...) { //Json constructor - ignored by Room @Ignore public WeatherEntry(int weatherIconId, Date date, // (!) Only one constructor should be exposed to Room ... @Entity constructors
  36. 36. #gdg_kharkiv_center @Dao
  37. 37. #gdg_kharkiv_center @Dao public interface WeatherDao { @Query("SELECT * FROM weather") List<WeatherEntry> getAll(); @Insert(onConflict = OnConflictStrategy.REPLACE) void insertAll(WeatherEntry... weatherEntries); @Delete void delete(WeatherEntry weatherEntry); } @Dao declaration
  38. 38. #gdg_kharkiv_center @Database
  39. 39. #gdg_kharkiv_center @Database(entities = {WeatherEntry.class}, version = 1) @TypeConverters(DateConverter.class) public abstract class AppDatabase extends RoomDatabase { public abstract WeatherDao weatherDao(); } @Database declaration
  40. 40. #gdg_kharkiv_center private static final String DATABASE_NAME = "weather"; private static final Object LOCK = new Object(); private static volatile AppDatabase sInstance; public static AppDatabase getInstance(Context context) { if (sInstance == null) { synchronized (LOCK) { if (sInstance == null) { sInstance = Room.databaseBuilder(context.getApplicationContext(), AppDatabase.class, AppDatabase.DATABASE_NAME).build(); } }} return sInstance; } @Database - a singleton
  41. 41. #gdg_kharkiv_center class DateConverter { @TypeConverter public static Date toDate(Long timestamp) { return timestamp == null ? null : new Date(timestamp); } @TypeConverter public static Long toTimestamp(Date date) { return date == null ? null : date.getTime(); } } Type converters
  42. 42. #gdg_kharkiv_center Alternatives
  43. 43. Repository Single source of trust
  44. 44. #gdg_kharkiv_center public class WeatherRepository { public synchronized static WeatherRepository getInstance(); public synchronized void initializeData(); private void deleteOldData(); private boolean isFetchNeeded(); private void startFetchWeatherService(); } Repository pattern
  45. 45. #gdg_kharkiv_center mWeatherNetworkDataSource = weatherNetworkDataSource; LiveData<WeatherEntry[]> networkData = mWeatherNetworkDataSource.getCurrentWeatherForecasts(); networkData.observeForever(newForecastsFromNetwork -> { mExecutors.diskIO().execute(() -> { mWeatherDao.bulkInsert(newForecastsFromNetwork); Log.d(LOG_TAG, "New values inserted"); }); }); Repository - fetch data from network Get and observe
  46. 46. #gdg_kharkiv_center private WeatherNetworkDataSource(Context context, AppExecutors executors) { mContext = context; mExecutors = executors; mDownloadedWeatherForecasts = new MutableLiveData<WeatherEntry[]>(); } Repository - use LiveData LiveData
  47. 47. #gdg_kharkiv_center private boolean isFetchNeeded() { Date today = CustomDateUtils.getNormalizedUtcDateForToday(); int count = mWeatherDao.countAllFutureWeather(today); return (count < WeatherNetworkDataSource.NUM_DAYS); } Check when to fetch
  48. 48. #gdg_kharkiv_center public synchronized void initializeData() { if (mInitialized) return; mInitialized = true; mExecutors.diskIO().execute(() -> { if (isFetchNeeded()) { startFetchWeatherService(); } }); } Check when to fetch Check if fetch needed
  49. 49. #gdg_kharkiv_center Display the data
  50. 50. #gdg_kharkiv_center public class DetailActivity extends LifecycleActivity { DetailActivityViewModel viewModel; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); ... viewModel = ViewModelProviders.of(this).get(DetailActivityViewModel.class); viewModel.getWeather().observe(this, weatherEntry -> { if(weatherEntry!=null) { bindWeatherToUI(weatherEntry); } }); } And again - observe LiveData
  51. 51. Testing Sneak peek :)
  52. 52. #gdg_kharkiv_center UI Controller - Instrumentation
  53. 53. #gdg_kharkiv_center ViewModel - JUnit
  54. 54. #gdg_kharkiv_center Repository - JUnit, MockWebServer
  55. 55. Latest updates From Alpha to Beta
  56. 56. #gdg_kharkiv_center September - October updates October 5, 2017 - Beta 2 - improved LiveDataReactiveStreams, - FullLifecycleObserver for Java 8, - Handling @Query methods with @NonNull annotations, - Still requires proguard settings to keep android.arch.lifecycle.GeneratedAdapter 1.0.0 Alpha 9-1 - Support Library 26.1.0, AppCompatActivity and Support Fragment now implement the LifecycleOwner interface - LifecycleActivity & LifecycleFragment are now deprecated - New Library: Paging
  57. 57. #gdg_kharkiv_center Paging Library - DataSource, - PagedList - PagedListAdapter - KeyedDataSource if you need to use data from item N-1 to load item N - TiledDataSource - LivePagedListProvider
  58. 58. #gdg_kharkiv_center Paging Library - Annotations on DAO @Query("select * from users WHERE age > :age order by name DESC, id ASC") TiledDataSource<User> usersOlderThan(int age); @Query("SELECT * from users order WHERE age > :age order by name DESC, id ASC") public abstract LivePagedListProvider<Integer, User> usersOlderThan(int age);
  59. 59. #gdg_kharkiv_center Paging Library - flow
  60. 60. Almost there... Scalability
  61. 61. #gdg_kharkiv_center Typical questions What if... I use RxJava? I already have MVP? I love Kotlin? I’m working on legacy project?
  62. 62. #gdg_kharkiv_center The Answer is...
  63. 63. #gdg_kharkiv_center What to read :) Guide to App Architecture https://developer.android.com/topic/libraries/architecture/guide.html Architecture Components https://developer.android.com/topic/libraries/architecture/index.html I/O ‘17 Architecture Components Introduction - https://youtu.be/FrteWKKVyzI Solving the Lifecycle Problem - https://youtu.be/bEKNi1JOrNs Persistence and Offline - https://youtu.be/MfHsPGQ6bgE Architecture Components on GDD Europe - https://youtu.be/Ts-uxYiBEQ8 GDD Europe CodeLabs g.co/codelabs/gdd17 Google Github samples https://github.com/googlesamples/android-architecture-components
  64. 64. #gdg_kharkiv_center Alternatives to consider Moxy https://github.com/Arello-Mobile/Moxy Mosby https://github.com/sockeqwe/mosby Android MVP Helper https://github.com/Ufkoku/AndroidMVPHelper Clean Architecture https://github.com/android10/Android-CleanArchitecture Reark https://github.com/reark/reark MVP + Dagger2 + Rx https://android.jlelse.eu/mvp-dagger-2-rx-clean-modern-android-app- code-74f63c9a6f2f Architecture the Lost Years by Uncle Bob https://youtu.be/WpkDN78P884
  65. 65. #gdg_kharkiv_center Where to go :)
  66. 66. #gdg_kharkiv_center Where to go :)
  67. 67. Constantine Mars @ConstantineMars +ConstantineMars Thank you! Q&A Mobile Architecture Club

×