Share
Embed
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
Transcript
55 slides
-
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 -
Components Create an UI that automatically responds to lifecycle events.
Lifecycle Kotlin and Android Arch Components -
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 -
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 -
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 -
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 -
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) -
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 -
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 -
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 -
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 } }) -
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 -
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 -
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 -
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 -
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 -
@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 -
@Entity(tableName = "user_table") data class User(var created: Date = Date(),
var name: String = "", @PrimaryKey var id: Int = 0) Entities -
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 -
@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 -
@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 -
@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 -
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 -
@Database(entities = arrayOf(User::class), version = 1, exportSchema = true) @TypeConverters(Converters::class)
abstract class AppDatabase : RoomDatabase() { abstract fun UserDao(): UserDao } Database -
class MyApp : Application() { lateinit var mDataBase: AppDatabase override
fun onCreate() { super.onCreate() mDataBase = Room.databaseBuilder(this, AppDatabase::class.java, "users").build() } } Database -
@Provides @Singleton fun provideDB(context: Context): AppDatabase = Room.databaseBuilder(context, AppDatabase::class.java, “users")
.fallbackToDestructiveMigration() .build() Database -
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) } } -
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) } } -
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) } } -
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 } } -
Query @Query("SELECT * FROM users ORDER WHERE age>:age ORDER by
name DESC, id ASC") abstract fun usersOlderThan(age: Int): LivePagedListProvider<Int, User> -
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()) } }