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

Android Architecture Components with Kotlin

Android Architecture Components with Kotlin

A small set of slides showing the usages and introducing the concept of the arch components library

Adit Lal

June 29, 2018
Tweet

More Decks by Adit Lal

Other Decks in Programming

Transcript

  1. Introduction An application with a solid architecture should be: •Easy

    to scale and maintain. •Each component should be isolated and decoupled. •Easy to test Kotlin and Android Arch Components
  2. Components Create an UI that automatically responds to lifecycle events.

    Lifecycle LiveData Build data objects that notify views when underlying data changes Kotlin and Android Arch Components
  3. Components Create an UI that automatically responds to lifecycle events.

    Lifecycle LiveData ViewModel Build data objects that notify views when underlying data changes Store UI related data that isn’t destroyed on app rotation Kotlin and Android Arch Components
  4. Components Create an UI that automatically responds to lifecycle events.

    Lifecycle LiveData ViewModel Room Build data objects that notify views when underlying data changes Store UI related data that isn’t destroyed on app rotation Access your data with the power of SQLite and safety of in-app objects. Kotlin and Android Arch Components
  5. Kotlin and Android Arch Components /** * Displays a message

    when app comes to foreground and goes to background. */ class AppLifecycleObserver @Inject constructor(context: Context) : LifecycleObserver { @OnLifecycleEvent(Lifecycle.Event.ON_START) fun onEnterForeground() { enterForegroundToast.showAfterCanceling(enterBackgroundToast) } @OnLifecycleEvent(Lifecycle.Event.ON_STOP) fun onEnterBackground() { enterBackgroundToast.showAfterCanceling(enterForegroundToast) } } Lifecycle
  6. Kotlin and Android Arch Components class AppLifecycleObserver @Inject constructor(context: Context)

    : LifecycleObserver { @OnLifecycleEvent(Lifecycle.Event.ON_START) fun onEnterForeground() { enterForegroundToast.showAfterCanceling(enterBackgroundToast) } @OnLifecycleEvent(Lifecycle.Event.ON_STOP) fun onEnterBackground() { enterBackgroundToast.showAfterCanceling(enterForegroundToast) } } Lifecycle ProcessLifecycleOwner.get().lifecycle.addObserver(appLifecycleObserver)
  7. Kotlin and Android Arch Components /** * Displays a message

    when app comes to foreground and goes to background. */ class AppLifecycleObserver @Inject constructor(context: Context) : LifecycleObserver { @OnLifecycleEvent(Lifecycle.Event.ON_START) fun onEnterForeground() { enterForegroundToast.showAfterCanceling(enterBackgroundToast) } @OnLifecycleEvent(Lifecycle.Event.ON_STOP) fun onEnterBackground() { enterBackgroundToast.showAfterCanceling(enterForegroundToast) } } Lifecycle
  8. Kotlin and Android Arch Components /** * Displays a message

    when app comes to foreground and goes to background. */ class AppLifecycleObserver @Inject constructor(context: Context) : LifecycleObserver { @OnLifecycleEvent(Lifecycle.Event.ON_START) fun onEnterForeground() { enterForegroundToast.showAfterCanceling(enterBackgroundToast) } @OnLifecycleEvent(Lifecycle.Event.ON_STOP) fun onEnterBackground() { enterBackgroundToast.showAfterCanceling(enterForegroundToast) } } Lifecycle
  9. LiveData LiveData is an observable data holder. It lets the

    components in your app, usually the UI, observe data objects for changes. Kotlin and Android Arch Components
  10. LiveData var userLiveData : MutableLiveData<List<User>> = MutableLiveData(); userLiveData.value = User(id=1,

    name="John Doe”) //Activity or fragment viewModel.getUsers().observe( this, Observer { result -> run { //Handle Result } })
  11. ViewModel Observes the lifecycle state of the view, maintaining consistency

    during configuration changes and other Android lifecycle events. The ViewModel class is designed to store and manage UI-related data so that the data survives configuration changes such as screen rotations.  Kotlin and Android Arch Components
  12. class NoteViewModel @Inject constructor(var repo: NotesRepository) : ViewModel() { fun

    getNotes(sort: String): LiveData<List<Note>> { return repo.getAllNotes(sort = sort) } fun addNote(note: Note): LiveData<Note> { return repo.addNote(note = note) } fun deleteNote(note: Note): LiveData<Int> { return repo.deleteNote(note) } ViewModel
  13. class NoteViewModel @Inject constructor(var repo: NotesRepository) : ViewModel() { fun

    getNotes(sort: String): LiveData<List<Note>> { return repo.getAllNotes(sort = sort) } fun addNote(note: Note): LiveData<Note> { return repo.addNote(note = note) } fun deleteNote(note: Note): LiveData<Int> { return repo.deleteNote(note) } ViewModel
  14. class NoteViewModel @Inject constructor(var repo: NotesRepository) : ViewModel() { fun

    getNotes(sort: String): LiveData<List<Note>> { return repo.getAllNotes(sort = sort) } fun addNote(note: Note): LiveData<Note> { return repo.addNote(note = note) } fun deleteNote(note: Note): LiveData<Int> { return repo.deleteNote(note) } ViewModel
  15. class NotesListActivity : AppCompatActivity(){ private lateinit var notesList: ArrayList<Note> @Inject

    lateinit var viewModelFactory: ViewModelFactory private val viewModel by lazy { ViewModelProviders.of( this@NotesListActivity, viewModelFactory).get(NoteViewModel::class.java) } ... } ViewModel
  16. @Inject lateinit var viewModelFactory: ViewModelFactory private val viewModel by lazy

    { ViewModelProviders.of(this@NotesListActivity, viewModelFactory).get(NoteViewModel::class.java) } //Activity viewModel.getNotes(sort = sort).observe( this, Observer { data -> run { notesList.clear() notesList.addAll(data!!) adapter.updateItems(notesList) } }) ViewModel
  17. @Entity(tableName = "user_table") data class User(var created: Date = Date(),

    var name: String = "", @PrimaryKey var id: Int = 0) Entities
  18. interface BaseDao<T> { @Insert fun insert(vararg obj: T) } @Dao

    abstract class DataDao : BaseDao<Data>() { @Query("SELECT * FROM Data") abstract fun getData(): List<Data> } Dao
  19. @Dao interface UserDao { @Insert(onConflict = OnConflictStrategy.REPLACE) fun insert(user: User)

    @Delete fun delete(user: User) @Query("SELECT * FROM user_table") fun getUsers(): List<User> } Dao
  20. @Dao interface UserDao { @Insert(onConflict = OnConflictStrategy.REPLACE) fun insert(user: User)

    @Delete fun delete(user: User) @Query("SELECT * FROM user_table") fun getUsers(): List<User> } Dao
  21. @Dao interface UserDao { @Insert(onConflict = OnConflictStrategy.REPLACE) fun insert(user: User)

    @Delete fun delete(user: User) @Query("SELECT * FROM user_table") fun getUsers(): LiveData<List<User>> } Dao
  22. class UserAndAllPets { @Embedded var user: User? = null @Relation(parentColumn

    = “userId”, entityColumn = “owner”) var pets: List<Pet> = ArrayList() } //UserDao.kt @Transaction @Query(“SELECT * FROM Users”) List<UserAndAllPets> getUsers(); Dao
  23. @Database(entities = arrayOf(User::class), version = 1, exportSchema = true) @TypeConverters(Converters::class)

    abstract class AppDatabase : RoomDatabase() { abstract fun UserDao(): UserDao } Database
  24. class MyApp : Application() { lateinit var mDataBase: AppDatabase override

    fun onCreate() { super.onCreate() mDataBase = Room.databaseBuilder(this, AppDatabase::class.java, "users").build() } } Database
  25. class MyPagedListAdapter(diffCallback: DiffCallback<User>) : PagedListAdapter<User, MyPagedListAdapter.ViewHolder>(diffCallback) { PagedListAdapter override fun

    onBindViewHolder(holder: MyPagedListAdapter.ViewHolder?, position: Int) { getItem(position)?.let { holder?.setData(it) } } override fun onCreateViewHolder(parent: ViewGroup?, viewType: Int): MyPagedListAdapter.ViewHolder { val view = LayoutInflater.from(parent?.context).inflate(R.layout.item_user, parent, false) return ViewHolder(view) } }
  26. class MyPagedListAdapter(diffCallback: DiffCallback<User>) : PagedListAdapter<User, MyPagedListAdapter.ViewHolder>(diffCallback) { PagedListAdapter override fun

    onBindViewHolder(holder: MyPagedListAdapter.ViewHolder?, position: Int) { getItem(position)?.let { holder?.setData(it) } } override fun onCreateViewHolder(parent: ViewGroup?, viewType: Int): MyPagedListAdapter.ViewHolder { val view = LayoutInflater.from(parent?.context).inflate(R.layout.item_user, parent, false) return ViewHolder(view) } }
  27. class MyPagedListAdapter(diffCallback: DiffCallback<User>) : PagedListAdapter<User, MyPagedListAdapter.ViewHolder>(diffCallback) { PagedListAdapter override fun

    onBindViewHolder(holder: MyPagedListAdapter.ViewHolder?, position: Int) { getItem(position)?.let { holder?.setData(it) } } override fun onCreateViewHolder(parent: ViewGroup?, viewType: Int): MyPagedListAdapter.ViewHolder { val view = LayoutInflater.from(parent?.context).inflate(R.layout.item_user, parent, false) return ViewHolder(view) } }
  28. DiffCallback private val diffCallback = object : DiffUtil.ItemCallback<User>() { override

    fun areItemsTheSame(oldItem: User, newItem: User): Boolean = oldItem.id == newItem.id override fun areContentsTheSame(oldItem: User, newItem: User): Boolean = oldItem == newItem } }
  29. Query @Query("SELECT * FROM users ORDER WHERE age>:age ORDER by

    name DESC, id ASC") abstract fun usersOlderThan(age: Int): LivePagedListProvider<Int, User>
  30. ViewModel class UserViewModel(val db:AppDB) : ViewModel() { val users: LiveData<PagedList<User>>

    fun getUsersOlderThan(age) { users = db.userDao().usersOlderThan(age) .create(0, PagedList.Config.Builder() .setPageSize(20) .setPrefetchDistance(20) .setEnablePlaceholders(false) .build()) } }