• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1page.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>
34Users expect apps to be responsive and fast to load. An app with a slow startup
35time doesn’t meet this expectation, and can be disappointing to users. This
36sort of poor experience may cause a user to rate your app poorly on the Play
37store, or even abandon your app altogether.
38</p>
39
40<p>
41This document provides information to help you optimize your app’s launch time.
42It begins by explaining the internals of the launch process. Next, it discusses
43how to profile startup performance. Last, it describes some common startup-time
44issues, and gives some hints on how to address them.
45</p>
46
47<h2 id="internals">Launch Internals</h2>
48
49<p>
50App launch can take place in one of three states, each affecting how
51long it takes for your app to become visible to the user: cold start,
52warm start, and lukewarm start. In a cold start, your app starts from scratch.
53In the other states, the system needs to bring the app from the background to
54the foreground. We recommend that you always optimize based on an assumption of
55a cold start. Doing so can improve the performance of warm and lukewarm starts,
56as well.
57</p>
58
59<p>
60To optimize your app for fast startup, it’s useful to understand what’s
61happening at the system and app levels, and how they interact, in each of
62these states.
63</p>
64
65<h3 id="cold">Cold start</h3>
66
67<p>
68A cold start refers to an app’s starting from scratch: the system’s process
69has not, until this start, created the app’s process. Cold starts happen in
70cases such as your app’s being launched for the first time since the device
71booted, or since the system killed the app. This type of start presents the
72greatest challenge in terms of minimizing startup time, because the system
73and app have more work to do than in the other launch states.
74</p>
75
76<p>
77At 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>
90As soon as the system creates the app process, the app process is responsible
91for 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>
104Once the app process has completed the first draw, the system process swaps
105out the currently displayed background window, replacing it with the main
106activity. At this point, the user can start using the app.
107</p>
108
109<p>
110Figure 1 shows how the system and app processes hand off work between each
111other.
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>
122Performance issues can arise during creation of the app and
123creation of the activity.
124</p>
125
126<h4 id="app-creation">Application creation</h4>
127
128<p>
129When your application launches, the blank starting window remains on the screen
130until the system finishes drawing the app for the first time. At that point,
131the system process swaps out the starting window for your app, allowing the
132user to start interacting with the app.
133</p>
134
135<p>
136If you’ve overloaded {@link android.app.Application#onCreate() Application.oncreate()}
137in your own app, the app starts by calling this
138method on your app object. Afterwards, the app spawns the main thread, also
139known as the UI thread, and tasks it with creating your main activity.
140</p>
141
142<p>
143From this point, system- and app-level processes proceed in accordance with
144the <a href="{docRoot}guide/topics/processes/process-lifecycle.html">
145app lifecycle stages</a>.
146</p>
147
148<h4 id="act-creation">Activity creation</h4>
149
150<p>
151After the app process creates your activity, the activity performs the
152following 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>
164Typically, the
165{@link android.app.Activity#onCreate(android.os.Bundle) onCreate()}
166method has the greatest impact on load time, because it performs the work with
167the highest overhead: loading and inflating views, and initializing the objects
168needed for the activity to run.
169</p>
170
171<h3 id="warm">Warm start</h3>
172
173<p>
174A warm start of your application is much simpler and lower-overhead than a
175cold start. In a warm start, all the system does is bring your activity to
176the foreground. If all of your application’s activities are still resident in
177memory, then the app can avoid having to repeat object initialization, layout
178inflation, and rendering.
179</p>
180
181<p>
182However, if some memory has been purged in response to memory trimming
183events, such as
184{@link android.content.ComponentCallbacks2#onTrimMemory(int) onTrimMemory()},
185then those objects will need to be recreated in
186response to the warm start event.
187</p>
188
189<p>
190A warm start displays the same on-screen behavior as a cold start scenario:
191The system process displays a blank screen until the app has finished rendering
192the activity.
193</p>
194
195<h3 id="lukewarm">Lukewarm start</h3>
196
197<p>
198A lukewarm start encompasses some subset of the operations that
199take place during a cold start; at the same time, it represents less overhead
200than a warm start. There are many potential states that could be considered
201lukewarm 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>
219In order to properly diagnose start time performance, you can track metrics
220that 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>
226From Android 4.4 (API level 19), logcat includes an output line containing
227a value called {@code Displayed}. This value represents
228the amount of time elapsed between launching the process and finishing drawing
229the corresponding activity on the screen. The elapsed time encompasses the
230following 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>
242The reported log line looks similar to the following example:
243</p>
244
245<pre class="no-pretty-print">
246ActivityManager: Displayed com.android.myexample/.StartupTiming: +3s534ms
247</pre>
248
249<p>
250If you’re tracking logcat output from the command line, or in a terminal,
251finding the elapsed time is straightforward. To find elapsed time in
252Android Studio, you must disable filters in your logcat view. Disabling the
253filters is necessary because the system server, not the app itself, serves
254this log.
255</p>
256
257<p>
258Once you’ve made the appropriate settings, you can easily search for the
259correct term to see the time. Figure 2 shows how to disable filters, and,
260in the second line of output from the bottom, an example of logcat output of
261the {@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>
272The {@code Displayed} metric in the logcat output does not necessarily capture
273the amount of time until all resources are loaded and displayed: it leaves out
274resources that are not referenced in the layout file or that the app creates
275as part of object initialization. It excludes these resources because loading
276them is an inline process, and does not block the app’s initial display.
277</p>
278
279<h3 id="time-full">Time to full display</h3>
280
281<p>
282You can use the {@link android.app.Activity#reportFullyDrawn()} method to
283measure the elapsed time
284between application launch and complete display of all resources and view
285hierarchies. This can be valuable in cases where an app performs lazy loading.
286In lazy loading, an app does not block the initial drawing of the window, but
287instead asynchronously loads resources and updates the view hierarchy.
288</p>
289
290<p>
291If, due to lazy loading, an app’s initial display does not include all
292resources, you might consider the completed loading and display of all
293resources and views as a separate metric: For example, your UI might be
294fully loaded, with some text drawn, but not yet display images that the
295app must fetch from the network.
296</p>
297
298<p>
299To address this concern, you can manually call
300{@link android.app.Activity#reportFullyDrawn()}
301to let the system know that your activity is
302finished with its lazy loading. When you use this method, the value
303that logcat displays is the time elapsed
304since the creation of the application object, and the moment
305{@link android.app.Activity#reportFullyDrawn()} is called.
306</p>
307
308<p>
309If you learn that your display times are slower than you’d like, you can
310go on to try to identify the bottlenecks in the startup process.
311</p>
312
313<h4 id="bottlenecks">Identifying bottlenecks</h4>
314
315<p>
316Two good ways to look for bottlenecks are Android Studio’s Method Tracer tool
317and inline tracing. To learn about Method Tracer, see that tool’s
318<a href="{docRoot}studio/profile/am-methodtrace.html">documentation</a>.
319</p>
320
321<p>
322If you do not have access to the Method Tracer tool, or cannot start the tool
323at the correct time to gain log information, you can gain similar insight
324through inline tracing inside of your apps’ and activities’ {@code onCreate()}
325methods. To learn about inline tracing, see the reference documentation for
326the {@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>
333This section discusses several issues that often affect apps’ startup
334performance. These issues chiefly concern initializing app and activity
335objects, as well as the loading of screens.
336</p>
337
338<h3 id="heavy-app">Heavy app initialization</h3>
339
340<p>
341Launch performance can suffer when your code overrides the {@code Application}
342object, and executes heavy work or complex logic when initializing that object.
343Your app may waste time during startup if your Application subclasses perform
344initializations that don’t need to be done yet. Some initializations may be
345completely unnecessary: for example, initializing state information for the
346main activity, when the app has actually started up in response to an intent.
347With an intent, the app uses only a subset of the previously initialized state
348data.
349</p>
350
351<p>
352Other challenges during app initialization include garbage-collection events
353that are impactful or numerous, or disk I/O happening concurrently with
354initialization, further blocking the initialization process. Garbage collection
355is especially a consideration with the Dalvik runtime; the Art runtime performs
356garbage collection concurrently, minimizing that operation's impact.
357</p>
358
359<h4 id="diagnosing-1">Diagnosing the problem</h4>
360
361<p>
362You can use method tracing or inline tracing to try to diagnose the problem.
363</p>
364
365<h5>Method tracing</h5>
366
367<p>
368Running the Method Tracer tool reveals that the
369{@link android.app.Instrumentation#callApplicationOnCreate(android.app.Application) callApplicationOnCreate()}
370method eventually calls your {@code com.example.customApplication.onCreate}
371method. If the tool shows that these
372methods are taking a long time to finish executing, you should explore further
373to see what work is occurring there.
374</p>
375
376<h5>Inline tracing</h5>
377
378<p>
379Use inline tracing to investigate likely culprits including:
380</p>
381
382<ul>
383   <li>Your app’s 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>
394Whether the problem lies with unnecessary initializations or disk I/O,
395the solution calls for lazy-initializing objects: initializing only those
396objects that are immediately needed. For example, rather than creating global
397static objects, instead, move to a singleton pattern, where the app initalizes
398objects only the first time it accesses them.
399</p>
400
401<h3 id="heavy-act">Heavy activity initialization</h4>
402
403<p>
404Activity creation often entails a lot of high-overhead work. Often, there are
405opportunities to optimize this work to achieve performance improvements. Such
406common 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>
420In this case, as well, both method tracing and inline tracing can prove useful.
421</p>
422
423<h5>Method tracing</h5>
424
425<p>
426When running the Method Tracer tool, the particular areas to
427focus on your your app’s {@link android.app.Application} subclass constructors and
428{@code com.example.customApplication.onCreate()} methods.
429</p>
430
431<p>
432If the tool shows that these methods are taking a long time to finish
433executing, you should explore further to see what work is occurring there.
434</p>
435
436<h5>Inline tracing</h5>
437
438<p>
439Use inline tracing to investigate likely culprits including:
440</p>
441
442<ul>
443   <li>Your app’s 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>
453There are many potential bottlenecks, but two common problems and remedies
454are 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>
488You may wish to theme your app’s loading experience, so that the app’s
489launch screen is thematically consistent with the rest of the app, instead of
490with the system theming. Doing so can hide a slow activity launch.
491</p>
492
493<p>
494A common way to implement a themed launch screen is to use the the
495{@link android.R.attr#windowDisablePreview} theme attribute to turn off
496the initial blank screen
497that the system process draws when launching the app. However, this approach
498can result in a longer startup time than apps that don’t suppress the preview
499window. Also, it forces the user to wait with no feedback while the activity
500launches, making them wonder if the app is functioning properly.
501</p>
502
503<h4 id="diagnosing-3">Diagnosing the problem</h4>
504
505<p>
506You can often diagnose this problem by observing a slow response when a user
507launches your app. In such a case, the screen may seem to be frozen, or to
508have stopped responding to input.
509</p>
510
511<h4 id="solutions-3">Solutions to the problem</h4>
512
513<p>
514We recommend that, rather than disabling the preview window, you
515follow the common
516<a href="http://www.google.com/design/spec/patterns/launch-screens.html#">
517Material Design</a> patterns. You can use the activity's
518{@code windowBackground} theme attribute to provide a simple custom drawable
519for the starting activity.
520</p>
521
522<p>
523For example, you might create a new drawable file and reference it from the
524layout XML and app manifest file as follows:
525</p>
526
527<p>Layout XML file:</p>
528
529<pre>
530&lt;layer-list xmlns:android="http://schemas.android.com/apk/res/android" android:opacity="opaque"&gt;
531  &lt;!-- The background color, preferably the same as your normal theme --&gt;
532  &lt;item android:drawable="@android:color/white"/&gt;
533  &lt;!-- Your product logo - 144dp color version of your app icon --&gt;
534  &lt;item&gt;
535    &lt;bitmap
536      android:src="@drawable/product_logo_144dp"
537      android:gravity="center"/&gt;
538  &lt;/item&gt;
539&lt;/layer-list&gt;
540</pre>
541
542<p>Manifest file:</p>
543
544<pre>
545&lt;activity ...
546android:theme="@style/AppTheme.Launcher" /&gt;
547</pre>
548
549<p>
550The easiest way to transition back to your normal theme is to call
551{@link android.view.ContextThemeWrapper#setTheme(int) setTheme(R.style.AppTheme)}
552before calling {@code super.onCreate()} and {@code setContentView()}:
553</p>
554
555<pre class="no-pretty-print">
556public class MyMainActivity extends AppCompatActivity {
557  &#64;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