Lesson 8 - App Architecture (UI Layer)

Download as pptx, pdf, or txt
Download as pptx, pdf, or txt
You are on page 1of 42

Lesson 8:

App architecture
(UI layer)

This work is licensed under the


Android Development with Kotlin Apache 2 license. 1
v1.0
About this lesson
Lesson 8: App architecture (UI layer)
● Android app architecture
● ViewModel
● Data binding
● LiveData
● Transform LiveData
● Summary

This work is licensed under the


Android Development with Kotlin Apache 2 license. 2
Android app
architecture

This work is licensed under the


Android Development with Kotlin Apache 2 license. 3
Avoid short-term hacks

● External factors, such as tight deadlines, can lead to


poor decisions about app design and structure.
● Decisions have consequences for future work (app can
be harder to maintain long-term).
● Need to balance on-time delivery and future
maintenance burden.

This work is licensed under the


Android Development with Kotlin Apache 2 license. 4
Examples of short-term hacks

● Tailoring your app to a specific device


● Blindly copying and pasting code into your files
● Placing all business logic in activity file
● Hardcoding user-facing strings in your code

This work is licensed under the


Android Development with Kotlin Apache 2 license. 5
Why you need good app
architecture
● Clearly defines where specific business logic belongs
● Makes it easier for developers to collaborate
● Makes your code easier to test
● Lets you benefit from already-solved problems
● Saves time and reduces technical debt as you extend
your app
This work is licensed under the
Android Development with Kotlin Apache 2 license. 6
Android Jetpack

● Android libraries that incorporate best practices and


provide backward compatibility in your apps
● Jetpack comprises the androidx.* package libraries

This work is licensed under the


Android Development with Kotlin Apache 2 license. 7
Separation of concerns

res/
layout
UI Controller
(Activity/Fragment
ViewModel
)

LiveData Data
Layer

This work is licensed under the


Android Development with Kotlin Apache 2 license. 8
Architecture components

● Architecture design patterns, like MVVM and MVI,


describe a loose template for what the structure of your
app should be.
● Jetpack architecture components help you design
robust, testable, and maintainable apps.

This work is licensed under the


Android Development with Kotlin Apache 2 license. 9
ViewModel

This work is licensed under the


Android Development with Kotlin Apache 2 license. 10
Gradle: lifecycle extensions

In app/build.gradle file:

dependencies {
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:
$lifecycle_version"
implementation "androidx.activity:activity-ktx:$activity_version"

This work is licensed under the


Android Development with Kotlin Apache 2 license. 11
ViewModel

● Prepares data for the UI


● Must not reference activity, fragment, or views in view
hierarchy
● Scoped to a lifecycle (which activity and fragment have)
● Enables data to survive configuration changes
● Survives as long as the scope is alive

This work is licensed under the


Android Development with Kotlin Apache 2 license. 12
Lifetime of a ViewModel

This work is licensed under the


Android Development with Kotlin Apache 2 license. 13
Kabaddi Kounter

This work is licensed under the


Android Development with Kotlin Apache 2 license. 14
ViewModel class
abstract class ViewModel

This work is licensed under the


Android Development with Kotlin Apache 2 license. 15
Implement a ViewModel
class ScoreViewModel : ViewModel() {
var scoreA : Int = 0
var scoreB : Int = 0
fun incrementScore(isTeamA: Boolean) {
if (isTeamA) {
scoreA++
}
else {
scoreB++
}
}
}
This work is licensed under the
Android Development with Kotlin Apache 2 license. 16
Load and use a ViewModel
class MainActivity : AppCompatActivity() {
// Delegate provided by androidx.activity.viewModels
val viewModel: ScoreViewModel by viewModels()

override fun onCreate(savedInstanceState: Bundle?) {


...
val scoreViewA: TextView = findViewById(R.id.scoreA)
scoreViewA.text = viewModel.scoreA.toString()

}
This work is licensed under the
Android Development with Kotlin Apache 2 license. 17
Using a ViewModel
Within MainActivity onCreate():

val scoreViewA: TextView = findViewById(R.id.scoreA)


val plusOneButtonA: Button =
findViewById(R.id.plusOne_teamA)

plusOneButtonA.setOnClickListener {
viewModel.incrementScore(true)
scoreViewA.text = viewModel.scoreA.toString()
}

This work is licensed under the


Android Development with Kotlin Apache 2 license. 18
Data binding

This work is licensed under the


Android Development with Kotlin Apache 2 license. 19
ViewModels and data binding
● App architecture without data binding
UI Controller
ViewMode Views
(activity/fragment
(defined in XML
l with click
layout)
listeners)

● ViewModels can work in concert with data


binding
ViewMode Views
(defined in XML
l layout)

This work is licensed under the


Android Development with Kotlin Apache 2 license. 20
Data binding in XML revisited

Specify ViewModels in the data tag of a binding.


<layout>
<data>
<variable>
name="viewModel"

type="com.example.kabaddikounter.ScoreViewModel" />
</data>
<ConstraintLayout ../>
</layout>

This work is licensed under the


Android Development with Kotlin Apache 2 license. 21
Attaching a ViewModel to a data
binding
class MainActivity : AppCompatActivity() {

val viewModel: ScoreViewModel by viewModels()

override fun onCreate(savedInstanceState: Bundle?) {


super.onCreate(savedInstanceState)
val binding: ActivityMainBinding =
DataBindingUtil.setContentView(this,
R.layout.activity_main)

binding.viewModel = viewModel
...

This work is licensed under the


Android Development with Kotlin Apache 2 license. 22
Using a ViewModel from a data
binding
In activity_main.xml:

<TextView
android:id="@+id/scoreViewA"
android:text="@{viewModel.scoreA.toString()}" />

...

This work is licensed under the


Android Development with Kotlin Apache 2 license. 23
ViewModels and data binding

override fun onCreate(savedInstanceState: Bundle?) {


...
val binding: ActivityMainBinding =
DataBindingUtil.setContentView(this,
R.layout.activity_main)

binding.plusOneButtonA.setOnClickListener {
viewModel.incrementScore(true)
binding.scoreViewA.text = viewModel.scoreA.toString()
}
}

This work is licensed under the


Android Development with Kotlin Apache 2 license. 24
LiveData

This work is licensed under the


Android Development with Kotlin Apache 2 license. 25
Observer design pattern

● Subject maintains list of observers to notify when state


changes.
● Observers receive state changes from subject and
execute appropriate code.
● Observers can be added or removed at any time.

This work is licensed under the


Android Development with Kotlin Apache 2 license. 26
Observer design pattern
diagram
Observable

notify observe() notify observe()

Observer Observer

This work is licensed under the


Android Development with Kotlin Apache 2 license. 27
LiveData
● A lifecycle-aware data holder that can be observed
● Wrapper that can be used with any data including lists
(for example, LiveData<Int> holds an Int)
● Often used by ViewModels to hold individual data fields
● Observers (activity or fragment) can be added or removed
○ observe(owner: LifecycleOwner, observer: Observer)
removeObserver(observer: Observer)

This work is licensed under the


Android Development with Kotlin Apache 2 license. 28
LiveData versus
MutableLiveData
LiveData<T> MutableLiveData<T>

● getValue() ● getValue()
● postValue(value: T)
● setValue(value: T)

T is the type of data that’s stored in LiveData or


MutableLiveData.

This work is licensed under the


Android Development with Kotlin Apache 2 license. 29
Use LiveData in ViewModel
class ScoreViewModel : ViewModel() {

private val _scoreA = MutableLiveData<Int>(0)


val scoreA: LiveData<Int>
get() = _scoreA

fun incrementScore(isTeamA: Boolean) {


if (isTeamA) {
_scoreA.value = _scoreA.value!! + 1
}
...

This work is licensed under the


Android Development with Kotlin Apache 2 license. 30
Add an observer on LiveData
Set up click listener to increment ViewModel score:
binding.plusOneButtonA.setOnClickListener {
viewModel.incrementScore(true)
}

Create observer to update team A score on screen:


val scoreA_Observer = Observer<Int> { newValue ->
binding.scoreViewA.text = newValue.toString()
}

Add the observer onto scoreA LiveData in ViewModel:


viewModel.scoreA.observe(this, scoreA_Observer)

This work is licensed under the


Android Development with Kotlin Apache 2 license. 31
Two-way data binding

● We already have two-way binding with ViewModel and


LiveData.
● Binding to LiveData in XML eliminates need for an
observer in code.

This work is licensed under the


Android Development with Kotlin Apache 2 license. 32
Example layout XML
<layout>
<data>
<variable>
name="viewModel"
type="com.example.kabaddikounter.ScoreViewModel" />
</data>
<ConstraintLayout ..>
<TextView ...
android:id="@+id/scoreViewA"
android:text="@{viewModel.scoreA.toString()}" />
...
</ConstraintLayout>
</layout>
This work is licensed under the
Android Development with Kotlin Apache 2 license. 33
Example Activity
class MainActivity : AppCompatActivity() {
val viewModel: ScoreViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val binding: ActivityMainBinding = DataBindingUtil
.setContentView(this, R.layout.activity_main)
binding.viewModel = viewModel
binding.lifecycleOwner = this
binding.plusOneButtonA.setOnClickListener {
viewModel.incrementScore(true)
}
...
This work is licensed under the
Android Development with Kotlin Apache 2 license. 34
Example ViewModel
class ScoreViewModel : ViewModel() {
private val _scoreA = MutableLiveData<Int>(0)
val scoreA : LiveData<Int>
get() = _scoreA
private val _scoreB = MutableLiveData<Int>(0)
val scoreB : LiveData<Int>
get() = _scoreB
fun incrementScore(isTeamA: Boolean) {
if (isTeamA) {
_scoreA.value = _scoreA.value!! + 1
} else {
_scoreB.value = _scoreB.value!! + 1
}
}
}
This work is licensed under the
Android Development with Kotlin Apache 2 license. 35
Transform LiveData

This work is licensed under the


Android Development with Kotlin Apache 2 license. 36
Manipulating LiveData with
transformations

LiveData can be transformed into a new LiveData object.


● map()
● switchMap()

This work is licensed under the


Android Development with Kotlin Apache 2 license. 37
Example LiveData with
transformations

val result: LiveData<String> = Transformations.map(viewModel.scoreA)


{
x -> if (x > 10) "A Wins" else ""
}

This work is licensed under the


Android Development with Kotlin Apache 2 license. 38
Summary

This work is licensed under the


Android Development with Kotlin Apache 2 license. 39
Summary
In Lesson 8, you learned how to:
● Follow good app architecture design, and the separation-of-c
oncerns principle to make apps more maintainable and reduc
e technical debt

● Create a ViewModel
to hold data separately from a UI controller
● Use ViewModel
with data binding to make a responsive UI with less code
● Use observers to automatically get updates from LiveData
This work is licensed under the
Android Development with Kotlin Apache 2 license. 40
Learn More

● Guide to app architecture


● Android Jetpack
● ViewModel Overview
● Android architecture sample app
● ViewModelProvider
● Lifecycle Aware Data Loading with Architecture Components
● ViewModels and LiveData: Patterns + AntiPatterns

This work is licensed under the


Android Development with Kotlin Apache 2 license. 41
Pathway

Practice what you’ve learned by


completing the pathway:
Lesson 8: App architecture (UI layer)

This work is licensed under the


Android Development with Kotlin Apache 2 license. 42

You might also like