Learning from the expert for handling shift left and app performance improvement for mobile applications.
Recently, mobile applications have had more complexity than backend applications. To tackle such complexity, I present an experience from the mobile expert to address issues around app performance.
20. App Launch
1.Load and launch the app
2.Display a starting/preview window
3.Create the app proces
4.Create the app object
5.Launch the main thread
6.Create the entry point activity
7.Inflate view
8.Lay out the screen
9.Perform initial draw
21.
22.
23. App Launch
:start-time class StartTimeContentProvider : ContentProvider() {
override fun onCreate(): Boolean {
return true
}
companion object {
val startTime = SystemClock.uptimeMillis()
}
}
24. App Launch
:start-time class StartTimeContentProvider : ContentProvider() {
override fun onCreate(): Boolean {
return true
}
companion object {
val startTime = SystemClock.uptimeMillis()
}
}
26. App Launch
:start-time class FirstDrawListener private constructor(
private val view: View,
private val onFirstDrawCallback: OnFirstDrawCallback
) : ViewTreeObserver.OnDrawListener {
...
}
27. App Launch
:start-time class FirstDrawListener private constructor(
private val view: View,
private val onFirstDrawCallback: OnFirstDrawCallback
) : ViewTreeObserver.OnDrawListener {
override fun onDraw() { }
}
28. App Launch
:start-time class FirstDrawListener private constructor(
private val view: View,
private val onFirstDrawCallback: OnFirstDrawCallback
) : ViewTreeObserver.OnDrawListener {
init {
registerFirstDrawListener()
}
override fun onDraw() { }
}
29. App Launch
:start-time
class FirstDrawListener private constructor(
private val view: View,
private val onFirstDrawCallback: OnFirstDrawCallback
) : ViewTreeObserver.OnDrawListener {
init {
registerFirstDrawListener()
}
override fun onDraw() { }
private fun registerFirstDrawListener() {
if (view.viewTreeObserver.isAlive && view.isAttachedToWindow) {
view.viewTreeObserver.addOnDrawListener(this@FirstDrawListener)
} else {
view.addOnAttachStateChangeListener(object : View.OnAttachStateChangeListener {
override fun onViewAttachedToWindow(v: View?) {
if (view.viewTreeObserver.isAlive) {
view.viewTreeObserver.addOnDrawListener(this@FirstDrawListener)
}
view.removeOnAttachStateChangeListener(this)
}
override fun onViewDetachedFromWindow(v: View?) {
/*NoOp*/
}
})
}
}
}
30. App Launch
:start-time
class FirstDrawListener private constructor(
private val view: View,
private val onFirstDrawCallback: OnFirstDrawCallback
) : ViewTreeObserver.OnDrawListener {
init {
registerFirstDrawListener()
}
override fun onDraw() {
if (!onDrawInvoked) {
onDrawInvoked = true
onFirstDrawCallback.onDrawingStart()
...
}
}
private fun registerFirstDrawListener() {
...
}
}
31. App Launch
:start-time
FirstDrawListener.registerFirstDrawListener(view, object : FirstDrawListener.OnFirstDrawCallback {
override fun onDrawingStart() {
val startTIme = StartTimeContentProvider.startTime
val endTime = SystemClock.uptimeMillis()
val result = endTime - startTime
println("$TAG App took $result ms to launch")
}
override fun onDrawingFinish() {
...
}
})
32. App Launch
:start-time
FirstDrawListener.registerFirstDrawListener(view, object : FirstDrawListener.OnFirstDrawCallback {
override fun onDrawingStart() {
val startTIme = StartTimeContentProvider.startTime
val endTime = SystemClock.uptimeMillis()
val result = endTime - startTime
println("AppStartup took $result ms to launch")
}
override fun onDrawingFinish() {
...
}
})
41. Proguard
Rules
- Scanning the merged rules, see if there any
misconfiguration rules (check the consumer-
pro.rules!)
42. Proguard
Rules
- Scanning the merged rules, see if there any
misconfiguration rules (check the consumer-
pro.rules!)
- Let proguard playground help you!
44. Proguard
Rules
- Scanning the merged rules, see if there any
misconfiguration rules (check the consumer-
pro.rules!)
- Let proguard playground help you!
- Check the dex files method number!
48. App Size Take Away
- Check the proguard rules
- OTA everything that you can do
- Optimize assets
- Applied branch by abstraction where you can
hardcoded the features!
- App Bundle is requirement!
- Dynamic Feature Modules!
60. App Startup Take Away
- Do not blocking main-thread!
- Parallelise the tasks!
- Lazy initialization instead of eager initialization
- Watch out the class load time!
- Watch out multiple instance!
- Watch out CPU and Memory Pressure!
- Watch out multiple activity starts!
64. Don’t try to find the best
design in software
architecture; instead, strive for
the least worst combination of
trade-offs
- Neal Ford (Software Architecture: The hard Part)