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.

Stavro Xhardha

August 08, 2019
Tweet

Other Decks in Programming

Transcript

  1. 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)
  2. Testing - Unit testing - Instrumentation testing - Real device

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

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

    - MediaPlayer - Permissions - Notifications - Sharing - Slices
  5. Android Architecture Components - DataBinding - Lifecycles - LiveData -

    Navigation - Paging - Room - ViewModel - WorkManager Robust app, quick business solutions.
  6. 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>
  7. <?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>
  8. 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() }
  9. 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 }
  10. - Shrinks code - Keeps views super pasive - Angular

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

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

    - 1 Activity/Fragment for 1 ViewModel class UserDataViewModel : ViewModel() { override fun onCleared(){ super.onCleared() } }
  13. 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
  14. - 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>
  15. 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
  16. Room - Abstraction Layer over SQLite - Super easy to

    configure - Available for RxJava - Available for Kotlin Coroutines
  17. @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> }
  18. @Entity(tableName = "users") data class Name( @ColumnInfo(name = "user_name") val

    firstName: String, @ColumnInfo(name = “last_name”) val lastName: String )
  19. 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++
  20. 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>
  21. 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)
  22. 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 } }
  23. 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
  24. 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)
  25. Add more into Android - Retrofit & OkHttp - Dagger2

    - RxJava2 or Kotlin Coroutines - Picasso - Mockito/Mockito Android - Junit4 (or Junit5) - AndroidJunit4 - MockWebServer