1 page.title=Launch-Time Performance 2 @jd:body 3 4 <div id="qv-wrapper"> 5 <div id="qv"> 6 7 <h2>In this document</h2> 8 <ol> 9 <li><a href="#internals">Launch Internals</a> 10 <ol> 11 <li><a href="#cold">Cold start</a></li> 12 <li><a href="#warm">Warm start</a></li> 13 <li><a href="#lukewarm">Lukewarm start</a></li> 14 </ol> 15 </li> 16 <li><a href="#profiling">Profiling Launch Performance</a> 17 <ol> 18 <li><a href="#time-initial">Time to initial display</a></li> 19 <li><a href="#time-full">Time to full display</a></li> 20 </ol> 21 </li> 22 <li><a href="#common">Common Issues</a> 23 <ol> 24 <li><a href="#heavy-app">Heavy app initialization</a></li> 25 <li><a href="#heavy-act">Heavy activity initialization</a></li> 26 <li><a href="#themed">Themed launch screens</a></li> 27 </ol> 28 </li> 29 </ol> 30 </div> 31 </div> 32 33 <p> 34 Users expect apps to be responsive and fast to load. An app with a slow startup 35 time doesnt meet this expectation, and can be disappointing to users. This 36 sort of poor experience may cause a user to rate your app poorly on the Play 37 store, or even abandon your app altogether. 38 </p> 39 40 <p> 41 This document provides information to help you optimize your apps launch time. 42 It begins by explaining the internals of the launch process. Next, it discusses 43 how to profile startup performance. Last, it describes some common startup-time 44 issues, and gives some hints on how to address them. 45 </p> 46 47 <h2 id="internals">Launch Internals</h2> 48 49 <p> 50 App launch can take place in one of three states, each affecting how 51 long it takes for your app to become visible to the user: cold start, 52 warm start, and lukewarm start. In a cold start, your app starts from scratch. 53 In the other states, the system needs to bring the app from the background to 54 the foreground. We recommend that you always optimize based on an assumption of 55 a cold start. Doing so can improve the performance of warm and lukewarm starts, 56 as well. 57 </p> 58 59 <p> 60 To optimize your app for fast startup, its useful to understand whats 61 happening at the system and app levels, and how they interact, in each of 62 these states. 63 </p> 64 65 <h3 id="cold">Cold start</h3> 66 67 <p> 68 A cold start refers to an apps starting from scratch: the systems process 69 has not, until this start, created the apps process. Cold starts happen in 70 cases such as your apps being launched for the first time since the device 71 booted, or since the system killed the app. This type of start presents the 72 greatest challenge in terms of minimizing startup time, because the system 73 and app have more work to do than in the other launch states. 74 </p> 75 76 <p> 77 At the beginning of a cold start, the system has three tasks. These tasks are: 78 </p> 79 80 <ol style="1"> 81 <li>Loading and launching the app.</li> 82 <li>Displaying a blank starting window for the app immediately after launch. 83 </li> 84 <li>Creating the app 85 <a href="{docRoot}guide/components/processes-and-threads.html#Processes"> 86 process.</a></li> 87 </ol> 88 <br/> 89 <p> 90 As soon as the system creates the app process, the app process is responsible 91 for the next stages. These stages are: 92 </p> 93 94 <ol style="1"> 95 <li>Creating the app object.</li> 96 <li>Launching the main thread.</li> 97 <li>Creating the main activity.</li> 98 <li>Inflating views.</li> 99 <li>Laying out the screen.</li> 100 <li>Performing the initial draw.</li> 101 </ol> 102 103 <p> 104 Once the app process has completed the first draw, the system process swaps 105 out the currently displayed background window, replacing it with the main 106 activity. At this point, the user can start using the app. 107 </p> 108 109 <p> 110 Figure 1 shows how the system and app processes hand off work between each 111 other. 112 </p> 113 <br/> 114 115 <img src="{@docRoot}topic/performance/images/cold-launch.png"> 116 <p class="img-caption"> 117 <strong>Figure 1.</strong> A visual representation of the important parts of 118 a cold application launch. 119 </p> 120 121 <p> 122 Performance issues can arise during creation of the app and 123 creation of the activity. 124 </p> 125 126 <h4 id="app-creation">Application creation</h4> 127 128 <p> 129 When your application launches, the blank starting window remains on the screen 130 until the system finishes drawing the app for the first time. At that point, 131 the system process swaps out the starting window for your app, allowing the 132 user to start interacting with the app. 133 </p> 134 135 <p> 136 If youve overloaded {@link android.app.Application#onCreate() Application.oncreate()} 137 in your own app, the app starts by calling this 138 method on your app object. Afterwards, the app spawns the main thread, also 139 known as the UI thread, and tasks it with creating your main activity. 140 </p> 141 142 <p> 143 From this point, system- and app-level processes proceed in accordance with 144 the <a href="{docRoot}guide/topics/processes/process-lifecycle.html"> 145 app lifecycle stages</a>. 146 </p> 147 148 <h4 id="act-creation">Activity creation</h4> 149 150 <p> 151 After the app process creates your activity, the activity performs the 152 following operations: 153 </p> 154 155 <ol style="1"> 156 <li>Initializes values.</li> 157 <li>Calls constructors.</li> 158 <li>Calls the callback method, such as 159 {@link android.app.Activity#onCreate(android.os.Bundle) Activity.onCreate()}, 160 appropriate to the current lifecycle state of the activity.</li> 161 </ol> 162 163 <p> 164 Typically, the 165 {@link android.app.Activity#onCreate(android.os.Bundle) onCreate()} 166 method has the greatest impact on load time, because it performs the work with 167 the highest overhead: loading and inflating views, and initializing the objects 168 needed for the activity to run. 169 </p> 170 171 <h3 id="warm">Warm start</h3> 172 173 <p> 174 A warm start of your application is much simpler and lower-overhead than a 175 cold start. In a warm start, all the system does is bring your activity to 176 the foreground. If all of your applications activities are still resident in 177 memory, then the app can avoid having to repeat object initialization, layout 178 inflation, and rendering. 179 </p> 180 181 <p> 182 However, if some memory has been purged in response to memory trimming 183 events, such as 184 {@link android.content.ComponentCallbacks2#onTrimMemory(int) onTrimMemory()}, 185 then those objects will need to be recreated in 186 response to the warm start event. 187 </p> 188 189 <p> 190 A warm start displays the same on-screen behavior as a cold start scenario: 191 The system process displays a blank screen until the app has finished rendering 192 the activity. 193 </p> 194 195 <h3 id="lukewarm">Lukewarm start</h3> 196 197 <p> 198 A lukewarm start encompasses some subset of the operations that 199 take place during a cold start; at the same time, it represents less overhead 200 than a warm start. There are many potential states that could be considered 201 lukewarm starts. For instance: 202 </p> 203 204 <ul> 205 <li>The user backs out of your app, but then re-launches it. The process may 206 have continued to run, but the app must recreate the activity from scratch 207 via a call to 208 {@link android.app.Activity#onCreate(android.os.Bundle) onCreate()}.</li> 209 210 <li>The system evicts your app from memory, and then the user re-launches it. 211 The process and the Activity need to be restarted, but the task can 212 benefit somewhat from the saved instance state bundle passed into 213 {@link android.app.Activity#onCreate(android.os.Bundle) onCreate()}.</li> 214 </ul> 215 216 <h2 id="profiling">Profiling Launch Performance</h2> 217 218 <p> 219 In order to properly diagnose start time performance, you can track metrics 220 that show how long it takes your application to start. 221 </p> 222 223 <h3 id="time-initial">Time to initial display</h3> 224 225 <p> 226 From Android 4.4 (API level 19), logcat includes an output line containing 227 a value called {@code Displayed}. This value represents 228 the amount of time elapsed between launching the process and finishing drawing 229 the corresponding activity on the screen. The elapsed time encompasses the 230 following sequence of events: 231 </p> 232 233 <ol style="1"> 234 <li>Launch the process.</li> 235 <li>Initialize the objects.</li> 236 <li>Create and initialize the activity.</li> 237 <li>Inflate the layout.</li> 238 <li>Draw your application for the first time.</li> 239 </ol> 240 241 <p> 242 The reported log line looks similar to the following example: 243 </p> 244 245 <pre class="no-pretty-print"> 246 ActivityManager: Displayed com.android.myexample/.StartupTiming: +3s534ms 247 </pre> 248 249 <p> 250 If youre tracking logcat output from the command line, or in a terminal, 251 finding the elapsed time is straightforward. To find elapsed time in 252 Android Studio, you must disable filters in your logcat view. Disabling the 253 filters is necessary because the system server, not the app itself, serves 254 this log. 255 </p> 256 257 <p> 258 Once youve made the appropriate settings, you can easily search for the 259 correct term to see the time. Figure 2 shows how to disable filters, and, 260 in the second line of output from the bottom, an example of logcat output of 261 the {@code Displayed} time. 262 </p> 263 <br/> 264 265 <img src="{@docRoot}topic/performance/images/displayed-logcat.png"> 266 <p class="img-caption"> 267 <strong>Figure 2.</strong> Disabling filters, and 268 finding the {@code Displayed} value in logcat. 269 </p> 270 271 <p> 272 The {@code Displayed} metric in the logcat output does not necessarily capture 273 the amount of time until all resources are loaded and displayed: it leaves out 274 resources that are not referenced in the layout file or that the app creates 275 as part of object initialization. It excludes these resources because loading 276 them is an inline process, and does not block the apps initial display. 277 </p> 278 279 <h3 id="time-full">Time to full display</h3> 280 281 <p> 282 You can use the {@link android.app.Activity#reportFullyDrawn()} method to 283 measure the elapsed time 284 between application launch and complete display of all resources and view 285 hierarchies. This can be valuable in cases where an app performs lazy loading. 286 In lazy loading, an app does not block the initial drawing of the window, but 287 instead asynchronously loads resources and updates the view hierarchy. 288 </p> 289 290 <p> 291 If, due to lazy loading, an apps initial display does not include all 292 resources, you might consider the completed loading and display of all 293 resources and views as a separate metric: For example, your UI might be 294 fully loaded, with some text drawn, but not yet display images that the 295 app must fetch from the network. 296 </p> 297 298 <p> 299 To address this concern, you can manually call 300 {@link android.app.Activity#reportFullyDrawn()} 301 to let the system know that your activity is 302 finished with its lazy loading. When you use this method, the value 303 that logcat displays is the time elapsed 304 since the creation of the application object, and the moment 305 {@link android.app.Activity#reportFullyDrawn()} is called. 306 </p> 307 308 <p> 309 If you learn that your display times are slower than youd like, you can 310 go on to try to identify the bottlenecks in the startup process. 311 </p> 312 313 <h4 id="bottlenecks">Identifying bottlenecks</h4> 314 315 <p> 316 Two good ways to look for bottlenecks are Android Studios Method Tracer tool 317 and inline tracing. To learn about Method Tracer, see that tools 318 <a href="{docRoot}studio/profile/am-methodtrace.html">documentation</a>. 319 </p> 320 321 <p> 322 If you do not have access to the Method Tracer tool, or cannot start the tool 323 at the correct time to gain log information, you can gain similar insight 324 through inline tracing inside of your apps and activities {@code onCreate()} 325 methods. To learn about inline tracing, see the reference documentation for 326 the {@link android.os.Trace} functions, and for the 327 <a href="{docRoot}studio/profile/systrace-commandline.html">Systrace</a> tool. 328 </p> 329 330 <h2 id="common">Common Issues</h2> 331 332 <p> 333 This section discusses several issues that often affect apps startup 334 performance. These issues chiefly concern initializing app and activity 335 objects, as well as the loading of screens. 336 </p> 337 338 <h3 id="heavy-app">Heavy app initialization</h3> 339 340 <p> 341 Launch performance can suffer when your code overrides the {@code Application} 342 object, and executes heavy work or complex logic when initializing that object. 343 Your app may waste time during startup if your Application subclasses perform 344 initializations that dont need to be done yet. Some initializations may be 345 completely unnecessary: for example, initializing state information for the 346 main activity, when the app has actually started up in response to an intent. 347 With an intent, the app uses only a subset of the previously initialized state 348 data. 349 </p> 350 351 <p> 352 Other challenges during app initialization include garbage-collection events 353 that are impactful or numerous, or disk I/O happening concurrently with 354 initialization, further blocking the initialization process. Garbage collection 355 is especially a consideration with the Dalvik runtime; the Art runtime performs 356 garbage collection concurrently, minimizing that operation's impact. 357 </p> 358 359 <h4 id="diagnosing-1">Diagnosing the problem</h4> 360 361 <p> 362 You can use method tracing or inline tracing to try to diagnose the problem. 363 </p> 364 365 <h5>Method tracing</h5> 366 367 <p> 368 Running the Method Tracer tool reveals that the 369 {@link android.app.Instrumentation#callApplicationOnCreate(android.app.Application) callApplicationOnCreate()} 370 method eventually calls your {@code com.example.customApplication.onCreate} 371 method. If the tool shows that these 372 methods are taking a long time to finish executing, you should explore further 373 to see what work is occurring there. 374 </p> 375 376 <h5>Inline tracing</h5> 377 378 <p> 379 Use inline tracing to investigate likely culprits including: 380 </p> 381 382 <ul> 383 <li>Your apps initial {@link android.app.Application#onCreate()} 384 function.</li> 385 <li>Any global singleton objects your app initializes.</li> 386 <li>Any disk I/O, deserialization, or tight loops that might be occurring 387 during the bottleneck. 388 </ul> 389 390 391 <h4 id="solutions-1">Solutions to the problem</h4> 392 393 <p> 394 Whether the problem lies with unnecessary initializations or disk I/O, 395 the solution calls for lazy-initializing objects: initializing only those 396 objects that are immediately needed. For example, rather than creating global 397 static objects, instead, move to a singleton pattern, where the app initalizes 398 objects only the first time it accesses them. 399 </p> 400 401 <h3 id="heavy-act">Heavy activity initialization</h4> 402 403 <p> 404 Activity creation often entails a lot of high-overhead work. Often, there are 405 opportunities to optimize this work to achieve performance improvements. Such 406 common issues include: 407 </p> 408 409 <ul> 410 <li>Inflating large or complex layouts.</li> 411 <li>Blocking screen drawing on disk, or network I/O.</li> 412 <li>Loading and decoding bitmaps.</li> 413 <li>Rasterizing {@link android.graphics.drawable.VectorDrawable VectorDrawable} objects.</li> 414 <li>Initialization of other subsystems of the activity.</li> 415 </ul> 416 417 <h4 id="diagnosing-2">Diagnosing the problem</h4> 418 419 <p> 420 In this case, as well, both method tracing and inline tracing can prove useful. 421 </p> 422 423 <h5>Method tracing</h5> 424 425 <p> 426 When running the Method Tracer tool, the particular areas to 427 focus on your your apps {@link android.app.Application} subclass constructors and 428 {@code com.example.customApplication.onCreate()} methods. 429 </p> 430 431 <p> 432 If the tool shows that these methods are taking a long time to finish 433 executing, you should explore further to see what work is occurring there. 434 </p> 435 436 <h5>Inline tracing</h5> 437 438 <p> 439 Use inline tracing to investigate likely culprits including: 440 </p> 441 442 <ul> 443 <li>Your apps initial {@link android.app.Application#onCreate()} 444 function.</li> 445 <li>Any global singleton objects it initializes.</li> 446 <li>Any disk I/O, deserialization, or tight loops that might be occurring 447 during the bottleneck.</li> 448 </ul> 449 450 <h4 id="solutions-2">Solutions to the problem</h4> 451 452 <p> 453 There are many potential bottlenecks, but two common problems and remedies 454 are as follows: 455 </p> 456 457 <ul> 458 <li>The larger your view hierarchy, the more time the app takes to inflate 459 it. Two steps you can take to address this issue are: 460 461 <ul> 462 <li>Flattening your view hierarchy by reducing redundant or nested 463 layouts.</li> 464 465 <li>Not inflating parts of the UI that do not need to be visible during 466 launch. Instead, use use a {@link android.view.ViewStub} object as a 467 placeholder for sub-hierarchies that the app can inflate at a more 468 appropriate time.</li> 469 </ul> 470 </li> 471 472 <li>Having all of your resource initialization on the main 473 thread can also slow down startup. You can address this issue as follows: 474 475 <ul> 476 <li>Move all resource initialization so that the app can perform it 477 lazily on a different thread.</li> 478 <li>Allow the app to load and display your views, and then later 479 update visual properties that are dependent on bitmaps and other 480 resources.</li> 481 </ul> 482 </li> 483 484 <h3 id="themed">Themed launch screens</h3> 485 486 487 <p> 488 You may wish to theme your apps loading experience, so that the apps 489 launch screen is thematically consistent with the rest of the app, instead of 490 with the system theming. Doing so can hide a slow activity launch. 491 </p> 492 493 <p> 494 A common way to implement a themed launch screen is to use the the 495 {@link android.R.attr#windowDisablePreview} theme attribute to turn off 496 the initial blank screen 497 that the system process draws when launching the app. However, this approach 498 can result in a longer startup time than apps that dont suppress the preview 499 window. Also, it forces the user to wait with no feedback while the activity 500 launches, making them wonder if the app is functioning properly. 501 </p> 502 503 <h4 id="diagnosing-3">Diagnosing the problem</h4> 504 505 <p> 506 You can often diagnose this problem by observing a slow response when a user 507 launches your app. In such a case, the screen may seem to be frozen, or to 508 have stopped responding to input. 509 </p> 510 511 <h4 id="solutions-3">Solutions to the problem</h4> 512 513 <p> 514 We recommend that, rather than disabling the preview window, you 515 follow the common 516 <a href="http://www.google.com/design/spec/patterns/launch-screens.html#"> 517 Material Design</a> patterns. You can use the activity's 518 {@code windowBackground} theme attribute to provide a simple custom drawable 519 for the starting activity. 520 </p> 521 522 <p> 523 For example, you might create a new drawable file and reference it from the 524 layout XML and app manifest file as follows: 525 </p> 526 527 <p>Layout XML file:</p> 528 529 <pre> 530 <layer-list xmlns:android="http://schemas.android.com/apk/res/android" android:opacity="opaque"> 531 <!-- The background color, preferably the same as your normal theme --> 532 <item android:drawable="@android:color/white"/> 533 <!-- Your product logo - 144dp color version of your app icon --> 534 <item> 535 <bitmap 536 android:src="@drawable/product_logo_144dp" 537 android:gravity="center"/> 538 </item> 539 </layer-list> 540 </pre> 541 542 <p>Manifest file:</p> 543 544 <pre> 545 <activity ... 546 android:theme="@style/AppTheme.Launcher" /> 547 </pre> 548 549 <p> 550 The easiest way to transition back to your normal theme is to call 551 {@link android.view.ContextThemeWrapper#setTheme(int) setTheme(R.style.AppTheme)} 552 before calling {@code super.onCreate()} and {@code setContentView()}: 553 </p> 554 555 <pre class="no-pretty-print"> 556 public class MyMainActivity extends AppCompatActivity { 557 @Override 558 protected void onCreate(Bundle savedInstanceState) { 559 // Make sure this is before calling super.onCreate 560 setTheme(R.style.Theme_MyApp); 561 super.onCreate(savedInstanceState); 562 // ... 563 } 564 } 565 </pre> 566