Merge "Docs: Launch-time performance doc for upcoming Performance section on DAC." into nyc-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
a8fa5ffbbc
BIN
docs/html/topic/performance/images/cold-launch.png
Normal file
BIN
docs/html/topic/performance/images/cold-launch.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 12 KiB |
BIN
docs/html/topic/performance/images/displayed-logcat.png
Normal file
BIN
docs/html/topic/performance/images/displayed-logcat.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 46 KiB |
565
docs/html/topic/performance/launch-time.jd
Normal file
565
docs/html/topic/performance/launch-time.jd
Normal file
@@ -0,0 +1,565 @@
|
|||||||
|
page.title=Launch-Time Performance
|
||||||
|
@jd:body
|
||||||
|
|
||||||
|
<div id="qv-wrapper">
|
||||||
|
<div id="qv">
|
||||||
|
|
||||||
|
<h2>In this document</h2>
|
||||||
|
<ol>
|
||||||
|
<li><a href="#internals">Launch Internals</a>
|
||||||
|
<ol>
|
||||||
|
<li><a href="#cold">Cold start</a></li>
|
||||||
|
<li><a href="#warm">Warm start</a></li>
|
||||||
|
<li><a href="#lukewarm">Lukewarm start</a></li>
|
||||||
|
</ol>
|
||||||
|
</li>
|
||||||
|
<li><a href="#profiling">Profiling Launch Performance</a>
|
||||||
|
<ol>
|
||||||
|
<li><a href="#time-initial">Time to initial display</a></li>
|
||||||
|
<li><a href="#time-full">Time to full display</a></li>
|
||||||
|
</ol>
|
||||||
|
</li>
|
||||||
|
<li><a href="#common">Common Issues</a>
|
||||||
|
<ol>
|
||||||
|
<li><a href="#heavy-app">Heavy app initialization</a></li>
|
||||||
|
<li><a href="#heavy-act">Heavy activity initialization</a></li>
|
||||||
|
<li><a href="#themed">Themed launch screens</a></li>
|
||||||
|
</ol>
|
||||||
|
</li>
|
||||||
|
</ol>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Users expect apps to be responsive and fast to load. An app with a slow startup
|
||||||
|
time doesn’t meet this expectation, and can be disappointing to users. This
|
||||||
|
sort of poor experience may cause a user to rate your app poorly on the Play
|
||||||
|
store, or even abandon your app altogether.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
This document provides information to help you optimize your app’s launch time.
|
||||||
|
It begins by explaining the internals of the launch process. Next, it discusses
|
||||||
|
how to profile startup performance. Last, it describes some common startup-time
|
||||||
|
issues, and gives some hints on how to address them.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<h2 id="internals">Launch Internals</h2>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
App launch can take place in one of three states, each affecting how
|
||||||
|
long it takes for your app to become visible to the user: cold start,
|
||||||
|
warm start, and lukewarm start. In a cold start, your app starts from scratch.
|
||||||
|
In the other states, the system needs to bring the app from the background to
|
||||||
|
the foreground. We recommend that you always optimize based on an assumption of
|
||||||
|
a cold start. Doing so can improve the performance of warm and lukewarm starts,
|
||||||
|
as well.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
To optimize your app for fast startup, it’s useful to understand what’s
|
||||||
|
happening at the system and app levels, and how they interact, in each of
|
||||||
|
these states.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<h3 id="cold">Cold start</h3>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
A cold start refers to an app’s starting from scratch: the system’s process
|
||||||
|
has not, until this start, created the app’s process. Cold starts happen in
|
||||||
|
cases such as your app’s being launched for the first time since the device
|
||||||
|
booted, or since the system killed the app. This type of start presents the
|
||||||
|
greatest challenge in terms of minimizing startup time, because the system
|
||||||
|
and app have more work to do than in the other launch states.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
At the beginning of a cold start, the system has three tasks. These tasks are:
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<ol style="1">
|
||||||
|
<li>Loading and launching the app.</li>
|
||||||
|
<li>Displaying a blank starting window for the app immediately after launch.
|
||||||
|
</li>
|
||||||
|
<li>Creating the app
|
||||||
|
<a href="{docRoot}guide/components/processes-and-threads.html#Processes">
|
||||||
|
process.</a></li>
|
||||||
|
</ol>
|
||||||
|
<br/>
|
||||||
|
<p>
|
||||||
|
As soon as the system creates the app process, the app process is responsible
|
||||||
|
for the next stages. These stages are:
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<ol style="1">
|
||||||
|
<li>Creating the app object.</li>
|
||||||
|
<li>Launching the main thread.</li>
|
||||||
|
<li>Creating the main activity.</li>
|
||||||
|
<li>Inflating views.</li>
|
||||||
|
<li>Laying out the screen.</li>
|
||||||
|
<li>Performing the initial draw.</li>
|
||||||
|
</ol>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Once the app process has completed the first draw, the system process swaps
|
||||||
|
out the currently displayed background window, replacing it with the main
|
||||||
|
activity. At this point, the user can start using the app.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Figure 1 shows how the system and app processes hand off work between each
|
||||||
|
other.
|
||||||
|
</p>
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
<img src="{@docRoot}performance/images/cold-launch.png">
|
||||||
|
<p class="img-caption">
|
||||||
|
<strong>Figure 1.</strong> A visual representation of the important parts of
|
||||||
|
a cold application launch.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Performance issues can arise during creation of the app and
|
||||||
|
creation of the activity.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<h4 id="app-creation">Application creation</h4>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
When your application launches, the blank starting window remains on the screen
|
||||||
|
until the system finishes drawing the app for the first time. At that point,
|
||||||
|
the system process swaps out the starting window for your app, allowing the
|
||||||
|
user to start interacting with the app.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
If you’ve overloaded {@link android.app.Application#onCreate() Application.oncreate()}
|
||||||
|
in your own app, the app starts by calling this
|
||||||
|
method on your app object. Afterwards, the app spawns the main thread, also
|
||||||
|
known as the UI thread, and tasks it with creating your main activity.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
From this point, system- and app-level processes proceed in accordance with
|
||||||
|
the <a href="{docRoot}guide/topics/processes/process-lifecycle.html">
|
||||||
|
app lifecycle stages</a>.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<h4 id="act-creation">Activity creation</h4>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
After the app process creates your activity, the activity performs the
|
||||||
|
following operations:
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<ol style="1">
|
||||||
|
<li>Initializes values.</li>
|
||||||
|
<li>Calls constructors.</li>
|
||||||
|
<li>Calls the callback method, such as
|
||||||
|
{@link android.app.Activity#onCreate(android.os.Bundle) Activity.onCreate()},
|
||||||
|
appropriate to the current lifecycle state of the activity.</li>
|
||||||
|
</ol>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Typically, the
|
||||||
|
{@link android.app.Activity#onCreate(android.os.Bundle) onCreate()}
|
||||||
|
method has the greatest impact on load time, because it performs the work with
|
||||||
|
the highest overhead: loading and inflating views, and initializing the objects
|
||||||
|
needed for the activity to run.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<h3 id="warm">Warm start</h3>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
A warm start of your application is much simpler and lower-overhead than a
|
||||||
|
cold start. In a warm start, all the system does is bring your activity to
|
||||||
|
the foreground. If all of your application’s activities are still resident in
|
||||||
|
memory, then the app can avoid having to repeat object initialization, layout
|
||||||
|
inflation, and rendering.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
However, if some memory has been purged in response to memory trimming
|
||||||
|
events, such as
|
||||||
|
{@link android.content.ComponentCallbacks2#onTrimMemory(int) onTrimMemory()},
|
||||||
|
then those objects will need to be recreated in
|
||||||
|
response to the warm start event.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
A warm start displays the same on-screen behavior as a cold start scenario:
|
||||||
|
The system process displays a blank screen until the app has finished rendering
|
||||||
|
the activity.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<h3 id="lukewarm">Lukewarm start</h3>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
A lukewarm start encompasses some subset of the operations that
|
||||||
|
take place during a cold start; at the same time, it represents less overhead
|
||||||
|
than a warm start. There are many potential states that could be considered
|
||||||
|
lukewarm starts. For instance:
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li>The user backs out of your app, but then re-launches it. The process may
|
||||||
|
have continued to run, but the app must recreate the activity from scratch
|
||||||
|
via a call to
|
||||||
|
{@link android.app.Activity#onCreate(android.os.Bundle) onCreate()}.</li>
|
||||||
|
|
||||||
|
<li>The system evicts your app from memory, and then the user re-launches it.
|
||||||
|
The process and the Activity need to be restarted, but the task can
|
||||||
|
benefit somewhat from the saved instance state bundle passed into
|
||||||
|
{@link android.app.Activity#onCreate(android.os.Bundle) onCreate()}.</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<h2 id="profiling">Profiling Launch Performance</h2>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
In order to properly diagnose start time performance, you can track metrics
|
||||||
|
that show how long it takes your application to start.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<h3 id="time-initial">Time to initial display</h3>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
From Android 4.4 (API level 19), logcat includes an output line containing
|
||||||
|
a value called {@code Displayed}. This value represents
|
||||||
|
the amount of time elapsed between launching the process and finishing drawing
|
||||||
|
the corresponding activity on the screen. The elapsed time encompasses the
|
||||||
|
following sequence of events:
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<ol style="1">
|
||||||
|
<li>Launch the process.</li>
|
||||||
|
<li>Initialize the objects.</li>
|
||||||
|
<li>Create and initialize the activity.</li>
|
||||||
|
<li>Inflate the layout.</li>
|
||||||
|
<li>Draw your application for the first time.</li>
|
||||||
|
</ol>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
The reported log line looks similar to the following example:
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<pre class="no-pretty-print">
|
||||||
|
ActivityManager: Displayed com.android.myexample/.StartupTiming: +3s534ms
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
If you’re tracking logcat output from the command line, or in a terminal,
|
||||||
|
finding the elapsed time is straightforward. To find elapsed time in
|
||||||
|
Android Studio, you must disable filters in your logcat view. Disabling the
|
||||||
|
filters is necessary because the system server, not the app itself, serves
|
||||||
|
this log.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Once you’ve made the appropriate settings, you can easily search for the
|
||||||
|
correct term to see the time. Figure 2 shows how to disable filters, and,
|
||||||
|
in the second line of output from the bottom, an example of logcat output of
|
||||||
|
the {@code Displayed} time.
|
||||||
|
</p>
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
<img src="{@docRoot}performance/images/displayed-logcat.png">
|
||||||
|
<p class="img-caption">
|
||||||
|
<strong>Figure 2.</strong> Disabling filters, and
|
||||||
|
finding the {@code Displayed} value in logcat.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
The {@code Displayed} metric in the logcat output does not necessarily capture
|
||||||
|
the amount of time until all resources are loaded and displayed: it leaves out
|
||||||
|
resources that are not referenced in the layout file or that the app creates
|
||||||
|
as part of object initialization. It excludes these resources because loading
|
||||||
|
them is an inline process, and does not block the app’s initial display.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<h3 id="time-full">Time to full display</h3>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
You can use the {@link android.app.Activity#reportFullyDrawn()} method to
|
||||||
|
measure the elapsed time
|
||||||
|
between application launch and complete display of all resources and view
|
||||||
|
hierarchies. This can be valuable in cases where an app performs lazy loading.
|
||||||
|
In lazy loading, an app does not block the initial drawing of the window, but
|
||||||
|
instead asynchronously loads resources and updates the view hierarchy.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
If, due to lazy loading, an app’s initial display does not include all
|
||||||
|
resources, you might consider the completed loading and display of all
|
||||||
|
resources and views as a separate metric: For example, your UI might be
|
||||||
|
fully loaded, with some text drawn, but not yet display images that the
|
||||||
|
app must fetch from the network.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
To address this concern, you can manually call
|
||||||
|
{@link android.app.Activity#reportFullyDrawn()}
|
||||||
|
to let the system know that your activity is
|
||||||
|
finished with its lazy loading. When you use this method, the value
|
||||||
|
that logcat displays is the time elapsed
|
||||||
|
since the creation of the application object, and the moment
|
||||||
|
{@link android.app.Activity#reportFullyDrawn()} is called.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
If you learn that your display times are slower than you’d like, you can
|
||||||
|
go on to try to identify the bottlenecks in the startup process.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<h4 id="bottlenecks">Identifying bottlenecks</h4>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Two good ways to look for bottlenecks are Android Studio’s Method Tracer tool
|
||||||
|
and inline tracing. To learn about Method Tracer, see that tool’s
|
||||||
|
<a href="{docRoot}studio/profile/am-methodtrace.html">documentation</a>.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
If you do not have access to the Method Tracer tool, or cannot start the tool
|
||||||
|
at the correct time to gain log information, you can gain similar insight
|
||||||
|
through inline tracing inside of your apps’ and activities’ {@code onCreate()}
|
||||||
|
methods. To learn about inline tracing, see the reference documentation for
|
||||||
|
the {@link android.os.Trace} functions, and for the
|
||||||
|
<a href="{docRoot}studio/profile/systrace-commandline.html">Systrace</a> tool.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<h2 id="common">Common Issues</h2>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
This section discusses several issues that often affect apps’ startup
|
||||||
|
performance. These issues chiefly concern initializing app and activity
|
||||||
|
objects, as well as the loading of screens.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<h3 id="heavy-app">Heavy app initialization</h3>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Launch performance can suffer when your code overrides the {@code Application}
|
||||||
|
object, and executes heavy work or complex logic when initializing that object.
|
||||||
|
Your app may waste time during startup if your Application subclasses perform
|
||||||
|
initializations that don’t need to be done yet. Some initializations may be
|
||||||
|
completely unnecessary: for example, initializing state information for the
|
||||||
|
main activity, when the app has actually started up in response to an intent.
|
||||||
|
With an intent, the app uses only a subset of the previously initialized state
|
||||||
|
data.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Other challenges during app initialization include garbage-collection events
|
||||||
|
that are impactful or numerous, or disk I/O happening concurrently with
|
||||||
|
initialization, further blocking the initialization process. Garbage collection
|
||||||
|
is especially a consideration with the Dalvik runtime; the Art runtime performs
|
||||||
|
garbage collection concurrently, minimizing that operation's impact.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<h4 id="diagnosing-1">Diagnosing the problem</h4>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
You can use method tracing or inline tracing to try to diagnose the problem.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<h5>Method tracing</h5>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Running the Method Tracer tool reveals that the
|
||||||
|
{@link android.app.Instrumentation#callApplicationOnCreate(android.app.Application) callApplicationOnCreate()}
|
||||||
|
method eventually calls your {@code com.example.customApplication.onCreate}
|
||||||
|
method. If the tool shows that these
|
||||||
|
methods are taking a long time to finish executing, you should explore further
|
||||||
|
to see what work is occurring there.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<h5>Inline tracing</h5>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Use inline tracing to investigate likely culprits including:
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li>Your app’s initial {@link android.app.Application#onCreate()}
|
||||||
|
function.</li>
|
||||||
|
<li>Any global singleton objects your app initializes.</li>
|
||||||
|
<li>Any disk I/O, deserialization, or tight loops that might be occurring
|
||||||
|
during the bottleneck.
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
|
||||||
|
<h4 id="solutions-1">Solutions to the problem</h4>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Whether the problem lies with unnecessary initializations or disk I/O,
|
||||||
|
the solution calls for lazy-initializing objects: initializing only those
|
||||||
|
objects that are immediately needed. For example, rather than creating global
|
||||||
|
static objects, instead, move to a singleton pattern, where the app initalizes
|
||||||
|
objects only the first time it accesses them.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<h3 id="heavy-act">Heavy activity initialization</h4>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Activity creation often entails a lot of high-overhead work. Often, there are
|
||||||
|
opportunities to optimize this work to achieve performance improvements. Such
|
||||||
|
common issues include:
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li>Inflating large or complex layouts.</li>
|
||||||
|
<li>Blocking screen drawing on disk, or network I/O.</li>
|
||||||
|
<li>Loading and decoding bitmaps.</li>
|
||||||
|
<li>Rasterizing {@link android.graphics.drawable.VectorDrawable VectorDrawable} objects.</li>
|
||||||
|
<li>Initialization of other subsystems of the activity.</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<h4 id="diagnosing-2">Diagnosing the problem</h4>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
In this case, as well, both method tracing and inline tracing can prove useful.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<h5>Method tracing</h5>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
When running the Method Tracer tool, the particular areas to
|
||||||
|
focus on your your app’s {@link android.app.Application} subclass constructors and
|
||||||
|
{@code com.example.customApplication.onCreate()} methods.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
If the tool shows that these methods are taking a long time to finish
|
||||||
|
executing, you should explore further to see what work is occurring there.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<h5>Inline tracing</h5>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Use inline tracing to investigate likely culprits including:
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li>Your app’s initial {@link android.app.Application#onCreate()}
|
||||||
|
function.</li>
|
||||||
|
<li>Any global singleton objects it initializes.</li>
|
||||||
|
<li>Any disk I/O, deserialization, or tight loops that might be occurring
|
||||||
|
during the bottleneck.</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<h4 id="solutions-2">Solutions to the problem</h4>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
There are many potential bottlenecks, but two common problems and remedies
|
||||||
|
are as follows:
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li>The larger your view hierarchy, the more time the app takes to inflate
|
||||||
|
it. Two steps you can take to address this issue are:
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li>Flattening your view hierarchy by reducing redundant or nested
|
||||||
|
layouts.</li>
|
||||||
|
|
||||||
|
<li>Not inflating parts of the UI that do not need to be visible during
|
||||||
|
launch. Instead, use use a {@link android.view.ViewStub} object as a
|
||||||
|
placeholder for sub-hierarchies that the app can inflate at a more
|
||||||
|
appropriate time.</li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li>Having all of your resource initialization on the main
|
||||||
|
thread can also slow down startup. You can address this issue as follows:
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li>Move all resource initialization so that the app can perform it
|
||||||
|
lazily on a different thread.</li>
|
||||||
|
<li>Allow the app to load and display your views, and then later
|
||||||
|
update visual properties that are dependent on bitmaps and other
|
||||||
|
resources.</li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<h3 id="themed">Themed launch screens</h3>
|
||||||
|
|
||||||
|
|
||||||
|
<p>
|
||||||
|
You may wish to theme your app’s loading experience, so that the app’s
|
||||||
|
launch screen is thematically consistent with the rest of the app, instead of
|
||||||
|
with the system theming. Doing so can hide a slow activity launch.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
A common way to implement a themed launch screen is to use the the
|
||||||
|
{@link android.R.attr#windowDisablePreview} theme attribute to turn off
|
||||||
|
the initial blank screen
|
||||||
|
that the system process draws when launching the app. However, this approach
|
||||||
|
can result in a longer startup time than apps that don’t suppress the preview
|
||||||
|
window. Also, it forces the user to wait with no feedback while the activity
|
||||||
|
launches, making them wonder if the app is functioning properly.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<h4 id="diagnosing-3">Diagnosing the problem</h4>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
You can often diagnose this problem by observing a slow response when a user
|
||||||
|
launches your app. In such a case, the screen may seem to be frozen, or to
|
||||||
|
have stopped responding to input.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<h4 id="solutions-3">Solutions to the problem</h4>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
We recommend that, rather than disabling the preview window, you
|
||||||
|
follow the common
|
||||||
|
<a href="http://www.google.com/design/spec/patterns/launch-screens.html#">
|
||||||
|
Material Design</a> patterns. You can use the activity's
|
||||||
|
{@code windowBackground} theme attribute to provide a simple custom drawable
|
||||||
|
for the starting activity.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
For example, you might create a new drawable file and reference it from the
|
||||||
|
layout XML and app manifest file as follows:
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>Layout XML file:</p>
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" android:opacity="opaque">
|
||||||
|
<!-- The background color, preferably the same as your normal theme -->
|
||||||
|
<item android:drawable="@android:color/white"/>
|
||||||
|
<!-- Your product logo - 144dp color version of your app icon -->
|
||||||
|
<item>
|
||||||
|
<bitmap
|
||||||
|
android:src="@drawable/product_logo_144dp"
|
||||||
|
android:gravity="center"/>
|
||||||
|
</item>
|
||||||
|
</layer-list>
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
<p>Manifest file:</p>
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
<activity ...
|
||||||
|
android:theme="@style/AppTheme.Launcher" />
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
The easiest way to transition back to your normal theme is to call
|
||||||
|
{@link android.view.ContextThemeWrapper#setTheme(int) setTheme(R.style.AppTheme)}
|
||||||
|
before calling {@code super.onCreate()} and {@code setContentView()}:
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<pre class="no-pretty-print">
|
||||||
|
public class MyMainActivity extends AppCompatActivity {
|
||||||
|
@Override
|
||||||
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
|
// Make sure this is before calling super.onCreate
|
||||||
|
setTheme(R.style.Theme_MyApp);
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</pre>
|
||||||
Reference in New Issue
Block a user