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

Destroy boilerplate code with Android Architecture Components

Destroy boilerplate code with Android Architecture Components

This talks goal is for anyone which knows Android or has programmed for Android and never used Android Architecture Components. It's a small introduction with a small "how-to" for each Android Architecture Components. At the end, a small comparison between 3 of the most used patterns in Android.

00d58a3791ba729539ed20ec0c2694a1?s=128

Stavro Xhardha

August 08, 2019
Tweet

Transcript

  1. Destroy boilerplate code with Android Architecture Components

  2. Stavro Xhardha Android Engineer @iKons @suspendingfunction

  3. Android JetPack

  4. AppCompat Support library for Android visual elements.

  5. Android KTX Kotlin extension for Android. sharedPreferences .edit() .putBoolean("key", value)

    .apply() sharedPreferences.edit { putBoolean("key", value) } //Under the hood: inline fun SharedPreferences.edit( commit: Boolean = false, action: SharedPreferences.Editor.() -> Unit)
  6. MultiDex - APK Extend 64K methods - MultiDex saves the

    day
  7. Testing - Unit testing - Instrumentation testing - Real device

    testing - UI Tests, Room etc. - E2E testing
  8. UI - Animation and Transitions - Auto, TV & wear

    - Emoji - Fragment - Layout - Palette
  9. Behavior - Download Manager - Media and Playback - ExoPlayer

    - MediaPlayer - Permissions - Notifications - Sharing - Slices
  10. None
  11. Android Architecture Components - DataBinding - Lifecycles - LiveData -

    Navigation - Paging - Room - ViewModel - WorkManager Robust app, quick business solutions.
  12. DataBinding findViewById<TextView>(R.id.sample_text).apply { text = viewModel.userName } <TextView android:text="@{viewmodel.userName}" />

  13. Usage of DataBinding android { ... dataBinding { enabled =

    true } } <layout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto"> <data> <variable name="viewmodel" type="com.myapp.data.UserDataViewModel" /> </data> <ConstraintLayout... /> </layout>
  14. <layout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto"> <data> <variable name="viewmodel" type="com.myapp.data.UserDataViewModel" /> </data> <ConstraintLayout...

    /> </layout>
  15. <?xml version="1.0" encoding="utf-8"?> <layout xmlns:android="http://schemas.android.com/apk/res/android"> <data> <variable name="viewmodel" type="com.myapp.data.UserDataViewModel"/> </data>

    <LinearLayout android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@{viewmodel.firstName}"/> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@{viewmodel.lastName}"/> </LinearLayout> </layout>
  16. override fun onCreate(savedInstanceState: Bundle?){ super.onCreate(savedInstanceState) viewModel = ViewModelProviders.of(this).get(UserDataViewModel.class) val binding:

    ActivityMainBinding = DataBindingUtil.setContentView( this, R.layout.activity_main) binding.viewModel = viewModel binding.lifecyclerOwner = this viewModel.loadUser() }
  17. Binding Adapters - Set of instructions to embed into view

    @BindingAdapter("imageUrl", "error") fun loadImage(view: ImageView, url: String, error: Drawable) { Picasso.get().load(url).error(error).into(view) //if else whatever }
  18. - Shrinks code - Keeps views super pasive - Angular

    lookalike - Long compiling time - Need for ViewBinding - JetPack Compose @Composable fun Greeting(name: String) { Text ("Hello $name!") }
  19. Lifecycles - Know state of the app - Prevent memory

    leaks - Manage configuration changes - Fragment Lifecycle - Activity - ViewModels - ….
  20. ViewModel - Holds data logic - LifecycleAware - Transfer Data

    - 1 Activity/Fragment for 1 ViewModel class UserDataViewModel : ViewModel() { override fun onCleared(){ super.onCleared() } }
  21. LiveData - Observables - Memory leaks - Manual data observation

  22. Implementation class UserDataViewModel : ViewModel() { val _firstName = MutableLiveData<String>()

    val firstName: LiveData<String> = _firstName init{ _firstName.value = “Ben” } // Rest of the UserDataViewModel… } - Sometimes too much variables
  23. Observe LiveData in Fragment viewModel.firstName.observe(this, Observer{ firstNameTextView.text = it })

  24. Navigation

  25. - Activity with Navigation should be called Passivity! <LinearLayout… >

    <fragment android:name="androidx.navigation.fragment.NavHostFragment" android:id="@+id/nav_host_fragment" android:layout_width="match_parent" android:layout_height="match_parent" app:defaultNavHost="true" app:navGraph="@navigation/nav_graph"/> </LinearLayout>
  26. viewTransactionsButton.setOnClickListener { view -> //Go to desired destination view.findNavController().navigate(R.id.viewTransactionsAction) }

    //Go back to desired destination view.findNavController().popBackStack(R.id.homeFragment, false) //mind the backstack
  27. Room - Abstraction Layer over SQLite - Super easy to

    configure - Available for RxJava - Available for Kotlin Coroutines
  28. @Database( entities = [User::class, Customer::class], version = 1, exportSchema =

    false ) abstract class MyDatabase : RoomDatabase() { abstract fun userDao(): UserDao } @Dao interface UserDao{ @Query("SELECT * FROM users") suspend fun selectAllUsers(): List<User> }
  29. @Entity(tableName = "users") data class Name( @ColumnInfo(name = "user_name") val

    firstName: String, @ColumnInfo(name = “last_name”) val lastName: String )
  30. Configuration Room.databaseBuilder( mContext, MyDatabase::class.java, DATABASE_NAME ).build()

  31. Paging Before - Scenario: Retreive data from network/database - Programatically

    check if reached end of the list - Remake the api/database call if reached the end, holding reference to the key - Load++
  32. Paging Library - Library does all for you - Support

    for RxJava - Handle request/response with livedata PagedList.Config.Builder() .setPageSize(INITIAL_PAGE_SIZE) .setEnablePlaceholders(false) .build() Room with Paging library @Query("SELECT * FROM persons") fun getAllPaged(): DataSource.Factory<Int, Person>
  33. class GalleryDataSource @Inject constructor(val mApi: MyApi) : PageKeyedDataSource<Int, UnsplashResult>(){ override

    fun loadBefore(params: LoadParams<Int>, callback: LoadCallback<Int, UnsplashResult>) {} override fun loadAfter(params: LoadParams<Int>, callback: LoadCallback<Int, UnsplashResult>) { } override fun loadInitial(params: LoadInitialParams<Int>, callback: LoadInitialCallback<Int, UnsplashResult>) { } } //Adapter class: class GalleryAdapter() : PagedListAdapter<UnsplashResult, GalleryAdapter.GalleryViewHolder>(DIFF_UTIL_GALLERY)
  34. class GalleryDataSourceFactory @Inject constructor(private val galleryDataSource: GalleryDataSource) : DataSource.Factory<Int, UnsplashResult>(){

    override fun create(): DataSource<Int, UnsplashResult> { mGalleryDataSouce = galleryDataSource sourceLiveData.postValue(mGalleryDataSouce) return galleryDataSource } }
  35. WorkManager - A mix between JobSceduler and BroadCastReceiver - Simple

    implementation - Constraints - No need to worry about reboot - Failure is managed - No need to register to manifest
  36. class PersonalWorkManager(val context: Context, parameters: WorkerParameters) : Worker(context, parameters){ override

    suspend fun doWork(): Result = Result.success() //or Result.failure() or Result.retry() } val constraints = Constraints.Builder() .setRequiredNetworkType(NetworkType.CONNECTED) .build() val compressionWork = OneTimeWorkRequestBuilder<PersonalWorkManager>() .setConstraints(constraints) .build() WorkManager.getInstance().enqueue(compressionWork)
  37. Add more into Android - Retrofit & OkHttp - Dagger2

    - RxJava2 or Kotlin Coroutines - Picasso - Mockito/Mockito Android - Junit4 (or Junit5) - AndroidJunit4 - MockWebServer
  38. Right architecture for Android - MVI - MVP - MVVM

  39. Questions….