Merge "docs: added "billions" doc in Distribute>Essentials" into mnc-mr-docs am: 3a766f6107
am: f89b0f11c6
* commit 'f89b0f11c619f6002fa92b7c5ada3da320a6d0d0':
docs: added "billions" doc in Distribute>Essentials
Change-Id: I6c324983121045f7360d30b9914c056465a84d02
This commit is contained in:
@@ -20,6 +20,9 @@ toc:
|
||||
- title: Auto App Quality
|
||||
path: /distribute/essentials/quality/auto.html
|
||||
|
||||
- title: Building for Billions
|
||||
path: /distribute/essentials/quality/billions.html
|
||||
|
||||
- title: Launch Checklist
|
||||
path: /distribute/tools/launch-checklist.html
|
||||
path_attributes:
|
||||
|
||||
@@ -29,6 +29,12 @@
|
||||
</a>
|
||||
</div>
|
||||
</li>
|
||||
<li class="nav-section">
|
||||
<div class="nav-section-header empty" style="font-weight:normal"><a href="<?cs var:toroot?>distribute/essentials/quality/billions.html">
|
||||
<span class="en">Building for Billions</span>
|
||||
</a>
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li class="nav-section">
|
||||
<div class="nav-section empty" style="font-weight:normal"><a href="<?cs var:toroot?>distribute/tools/launch-checklist.html" zh-cn-lang="发布检查清单">
|
||||
|
||||
778
docs/html/distribute/essentials/quality/billions.jd
Normal file
778
docs/html/distribute/essentials/quality/billions.jd
Normal file
@@ -0,0 +1,778 @@
|
||||
page.title=Building for Billions
|
||||
page.metaDescription=Best practices on how to optimize Android apps for low- and no-bandwidth and low-cost devices.
|
||||
page.image=/distribute/images/billions-guidelines.png
|
||||
|
||||
@jd:body
|
||||
|
||||
<!-- table of contents -->
|
||||
<div id="qv-wrapper"><div id="qv">
|
||||
<h2><a href="#connectivity">Connectivity</a></h2>
|
||||
<ol>
|
||||
<li><a href="#images">Optimize images</a></li>
|
||||
<li><a href="#network">Optimize networking</a></li>
|
||||
<li><a href="#transfer">Fine-tune data transfer</a></li>
|
||||
</ol>
|
||||
<h2><a href="#capability">Device Capability</a></h2>
|
||||
<ol>
|
||||
<li><a href="#screens">Support varying screen sizes</a></li>
|
||||
<li><a href="#compatibility">Backward compatibility</a></li>
|
||||
<li><a href="#memory">Efficient memory usage</a></li>
|
||||
</ol>
|
||||
|
||||
<h2><a href="#cost">Data Cost</a></h2>
|
||||
<ol>
|
||||
<li><a href="#appsize">Reduce app size</a></li>
|
||||
<li><a href="#configurablenetwork">Offer configurable network usage</a></li>
|
||||
</ol>
|
||||
|
||||
<h2><a href="#consumption">Battery Consumption</a></h2>
|
||||
<ol>
|
||||
<li><a href="#consumption-reduce">Reduce battery consumption</a></li>
|
||||
<li><a href="#consumption-benchmark">Benchmark battery usage</a></li>
|
||||
</ol>
|
||||
|
||||
<h2><a href="#contentsection">Content</a></h2>
|
||||
<ol>
|
||||
<li><a href="#content-responsive">Fast and responsive UI</a></li>
|
||||
<li><a href="#ui">UI Best practices</a></li>
|
||||
<li><a href="#localization">Localization</a></li>
|
||||
</ol>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- intro -->
|
||||
<p>Internet use—and smartphone penetration—is growing fastest in markets with
|
||||
low, intermittent, or expensive connectivity. Successful apps in these
|
||||
markets need to perform across a variety of speeds and devices, as well as
|
||||
conserve and share information about battery and data consumption.</p>
|
||||
|
||||
<p>To help you address these important considerations, we’ve compiled the
|
||||
following checklist. These do not follow a particular order, and as
|
||||
always it's a good idea to research particularities of any market or country
|
||||
you're targeting.
|
||||
</p>
|
||||
|
||||
<!-- connectivity -->
|
||||
<div class="headerLine">
|
||||
<h2 id="connectivity">Connectivity</h2>
|
||||
</div>
|
||||
|
||||
<p>Over half of the users in the world still experience your app over 2G
|
||||
connections. To improve their experience, optimize for no- and low-connection
|
||||
speeds. For offline and slow connections: store data, queue requests, and handle
|
||||
images for optimal performance.
|
||||
</p>
|
||||
|
||||
<h3 id="images">Optimize images</h3>
|
||||
<h4 id="images-format">Serve WebP images</h4>
|
||||
<ul>
|
||||
<li>Serve <a
|
||||
href="https://developers.google.com/speed/webp/">WebP</a> files over the
|
||||
network. WebP reduces image load times, saves network bandwidth, and often
|
||||
results in smaller file sizes than its PNG and JPG counterparts, with at
|
||||
least the same image quality. Even at lossy settings, WebP can produce a
|
||||
nearly identical image. Android has had lossy <a
|
||||
href="{@docRoot}guide/appendix/media-formats.html">WebP support</a> since
|
||||
Android 4.0 (API level 14: Ice Cream Sandwich) and support for lossless /
|
||||
transparent WebP since Android 4.2 (API level 17: Jelly Bean).</li>
|
||||
</ul>
|
||||
<h4 id="images-sizing">Dynamic image sizing</h4>
|
||||
<ul>
|
||||
<li>Have your apps request images at the targeted rendering size, and have
|
||||
your server provide those images to fit; the target rendering size will
|
||||
vary based on device specifications. Doing this minimizes the network
|
||||
overhead and reduces the amount of memory needed to hold each image,
|
||||
resulting in improved performance and user satisfaction.</li>
|
||||
<li>Your user experience degrades when users are waiting for images to
|
||||
download. Using appropriate image sizes helps to address these issues.
|
||||
Consider making image size requests based on network type or network
|
||||
quality; this size could be smaller than the target rendering size.</li>
|
||||
<li>Dynamic placeholders like <a
|
||||
href="{@docRoot}reference/android/support/v7/graphics/Palette.html">
|
||||
pre-computed palette values</a> or low-resolution thumbnails can improve
|
||||
the user experience while the image is being fetched.</li>
|
||||
</ul>
|
||||
<h4 id="images-libraries">Use image loading libraries</h4>
|
||||
<ul>
|
||||
<li>Your app should not have to fetch any image more than once. Image
|
||||
loading libraries such as <a class="external-link"
|
||||
href="https://github.com/bumptech/glide">Glide</a> and <a
|
||||
class="external-link" href="http://square.github.io/picasso/">Picasso</a>
|
||||
fetch the image, cache it, and provide hooks into your Views to show
|
||||
placeholder images until the actual images are ready. Because images are
|
||||
cached, these libraries return the local copy the next time they are
|
||||
requested.</li>
|
||||
<li>Image-loading libraries manage their cache, holding onto the most recent
|
||||
images so that your app storage doesn’t grow indefinitely.</li>
|
||||
</ul>
|
||||
|
||||
<h3 id="network">Optimize networking</h3>
|
||||
<h4 id="network-offline">Make your app usable offline</h4>
|
||||
<ul>
|
||||
<li>In places like subways, planes, elevators, and parking garages, it is
|
||||
common for devices to lose network connectivity. Creating a useful offline
|
||||
state results in users being able to interact with the app at all times, by
|
||||
presenting cached information. Ensure that your app is usable offline or
|
||||
when network connectivity is poor by storing data locally, caching data,
|
||||
and queuing outbound requests for when connectivity is restored.</li>
|
||||
<li>Where possible, apps should not notify users that connectivity has
|
||||
been lost. It is only when the user performs an operation where connectivity
|
||||
is essential that the user needs to be notified.</li>
|
||||
<li>When a device lacks connectivity, your app should batch up network
|
||||
requests—on behalf of the user—that can be executed when
|
||||
connectivity is restored. An example of this is an email client that allows
|
||||
users to compose, send, read, move, and delete existing mails even when the
|
||||
device is offline. These operations can be cached and executed when
|
||||
connectivity is restored. In doing so, the app is able to provide a similar
|
||||
user experience whether the device is online or offline.</li>
|
||||
</ul>
|
||||
<h4 id="network-arch">Use GcmNetworkManager and/or Content Providers</h4>
|
||||
<ul>
|
||||
<li>Ensure that your app stores all data on disk via a database or similar
|
||||
structure so that it performs optimally regardless of network conditions
|
||||
(for example, via SQLite + ContentProvider). The <a
|
||||
href="https://developers.google.com/cloud-messaging/network-manager">
|
||||
GCM Network Manager</a>
|
||||
(<a href="https://developers.google.com/android/reference/com/google/android/gms/gcm/GcmNetworkManager">
|
||||
<code>GcmNetworkManager</code></a>) can result in a robust mechanism to
|
||||
sync data with servers while <a
|
||||
href="{@docRoot}guide/topics/providers/content-providers.html">content
|
||||
providers</a> ({@link android.content.ContentProvider}) cache that data,
|
||||
combining to provide an architecture that enables a useful offline state.</li>
|
||||
<li>Apps should cache content that is fetched from the network. Before making
|
||||
subsequent requests, apps should display locally cached data. This ensures
|
||||
that the app is functional regardless of whether the device is offline or
|
||||
on a slow/unreliable network.</li>
|
||||
</ul>
|
||||
<h4 id="network-duplicate">Deduplicate network requests</h4>
|
||||
<ul>
|
||||
<li>An offline-first architecture initially tries to fetch data from local
|
||||
storage and, failing that, requests the data from the network. After being
|
||||
retrieved from the network, the data is cached locally for future
|
||||
retrieval. This helps to ensure that network requests for the same piece of
|
||||
data only occur once—the rest of the requests are satisfied locally. To
|
||||
achieve this, use a local database for long-lived data (usually
|
||||
{@link android.database.sqlite} or
|
||||
{@link android.content.SharedPreferences}).</li>
|
||||
<li>An offline-first architecture always looks for data locally first, then
|
||||
makes the request over the network. The response is cached and then returned
|
||||
locally. Such an architecture simplifies an app’s flow between offline and
|
||||
online states as one side fetches from the network to the cache, while the
|
||||
other retrieves data from the cache to present to the user.</li>
|
||||
<li>For transitory data, use a bounded disk cache such as a <a class="external-link"
|
||||
href="https://github.com/JakeWharton/DiskLruCache"><code>DiskLruCache</code>
|
||||
</a>. Data that doesn’t typically change should only be requested once over
|
||||
the network and cached for future use. Examples of such data are images and
|
||||
non-temporal documents like news articles or social posts.</li>
|
||||
</ul>
|
||||
|
||||
<h3 id="transfer">Fine-tune data transfer</h3>
|
||||
<h4 id="transfer-prioritize">Prioritize bandwidth</h4>
|
||||
<ul>
|
||||
<li>Writers of apps should not assume that any network that the device is
|
||||
connected to is long-lasting or reliable. For this reason, apps should
|
||||
prioritize network requests to display the most useful information to the
|
||||
user as soon as possible.</li>
|
||||
<li>Presenting users with visible and relevant information immediately is a
|
||||
better user experience than making them wait for information that might not
|
||||
be necessary. This reduces the time that the user has to wait and
|
||||
increases the usefulness of the app on slow networks.</li>
|
||||
<li>To achieve this, sequence your network requests such that text is
|
||||
fetched before rich media. Text requests tend to be smaller, compress
|
||||
better, and hence transfer faster, meaning that your app can display useful
|
||||
content quickly. For more information on managing network requests, visit
|
||||
the Android training on <a
|
||||
href="{@docRoot}training/basics/network-ops/managing.html">Managing Network
|
||||
Usage</a>.</li>
|
||||
</ul>
|
||||
<h4 id="network-bandwidth">Use less bandwidth on slower connections</h4>
|
||||
<ul>
|
||||
<li>The ability for your app to transfer data in a timely fashion is
|
||||
dependent on the network connection. Detecting the quality of the network
|
||||
and adjusting the way your app uses it can help provide an excellent user
|
||||
experience.</li>
|
||||
<li>You can use the following methods to detect the underlying network
|
||||
quality. Using the data from these methods, your app should tailor its use
|
||||
of the network to continue to provide a timely response to user actions:
|
||||
<ul>
|
||||
<li>{@link android.net.ConnectivityManager}>
|
||||
{@link android.net.ConnectivityManager#isActiveNetworkMetered}</li>
|
||||
<li>{@link android.net.ConnectivityManager}>
|
||||
{@link android.net.ConnectivityManager#getActiveNetworkInfo}</li>
|
||||
<li>{@link android.net.ConnectivityManager}>
|
||||
{@link android.net.ConnectivityManager#getNetworkCapabilities}</li>
|
||||
<li>{@link android.telephony.TelephonyManager}>
|
||||
{@link android.telephony.TelephonyManager#getNetworkType}</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>On slower connections, consider downloading only lower-resolution media
|
||||
or perhaps none at all. This ensures that your users are still able to use
|
||||
the app on slow connections. Where you don’t have an image or the image is
|
||||
still loading, you should always show a placeholder. You can create a
|
||||
dynamic placeholder by using the <a
|
||||
href="{@docRoot}tools/support-library/features.html#v7-palette">
|
||||
Palette library</a> to generate placeholder colors that match the target
|
||||
image.</li>
|
||||
<li>Prioritize network requests such that text is fetched before rich media.
|
||||
Text requests tend to be smaller, compress better, and hence transfer
|
||||
faster, meaning that your app can display useful content quickly. For more
|
||||
information on adjusting bandwidth based on network connection, see the
|
||||
Android training on <a
|
||||
href="{@docRoot}training/basics/network-ops/managing.html">Managing Network
|
||||
Usage</a>.</li>
|
||||
</ul>
|
||||
<h4 id="network-behavior">Detect network changes, then change app behavior</h4>
|
||||
<ul>
|
||||
<li>Network quality is not static; it changes based on location, network
|
||||
traffic, and local population density. Apps should detect changes in
|
||||
network and adjust bandwidth accordingly. By doing so, your app can tailor
|
||||
the user experience to the network quality. Detect network state using
|
||||
these methods:
|
||||
<ul>
|
||||
<li>{@link android.net.ConnectivityManager}>
|
||||
{@link android.net.ConnectivityManager#getActiveNetworkInfo}</li>
|
||||
<li>{@link android.net.ConnectivityManager}>
|
||||
{@link android.net.ConnectivityManager#getNetworkCapabilities}</li>
|
||||
<li>{@link android.telephony.TelephonyManager}>
|
||||
{@link android.telephony.TelephonyManager#getDataState}</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>As the network quality degrades, scale down the number and size of
|
||||
requests. As the connection quality improves, you can scale up your
|
||||
requests to optimal levels.</li>
|
||||
<li>On higher quality, unmetered networks, consider <a
|
||||
href="{@docRoot}training/efficient-downloads/efficient-network-access.html#PrefetchData">
|
||||
prefetching data</a> to make it available ahead of time. From a user
|
||||
experience standpoint, this might mean that news reader apps only fetch
|
||||
three articles at a time on 2G but fetch twenty articles at a time on
|
||||
Wi-Fi. For more information on adjusting app behavior based on network changes,
|
||||
visit the Android training on <a
|
||||
href="{@docRoot}training/monitoring-device-state/connectivity-monitoring.html">
|
||||
Monitoring the Connectivity Status</a>.</li>
|
||||
<li>The broadcast <a
|
||||
href="{@docRoot}reference/android/net/ConnectivityManager.html#CONNECTIVITY_ACTION">
|
||||
<code>CONNECTIVITY_CHANGE</code></a> is sent when a change in network
|
||||
connectivity occurs. When your app is in the foreground, you can call <a
|
||||
href="{@docRoot}reference/android/content/Context.html#registerReceiver(android.content.BroadcastReceiver,%20android.content.IntentFilter)">
|
||||
<code>registerReceiver</code></a> to receive this broadcast. After receiving
|
||||
the broadcast, you should reevaluate the current network state and adjust
|
||||
your UI and network usage appropriately. You should not declare this receiver
|
||||
in your manifest, as it will no longer function beginning with Android N.
|
||||
For more details see <a href="{@docRoot}preview/behavior-changes.html">
|
||||
Android N behavior changes</a>.</li>
|
||||
</ul>
|
||||
|
||||
<h3 class="rel-resources clearfloat">Related resources</h3>
|
||||
<div class="resource-widget resource-flow-layout col-13"
|
||||
data-query="collection:distribute/essentials/billionsquality/connectivity"
|
||||
data-sortOrder="-timestamp"
|
||||
data-cardSizes="6x3"
|
||||
data-maxResults="6"></div>
|
||||
|
||||
<!-- capability -->
|
||||
<div class="headerLine">
|
||||
<h2 id="capability">Device Capability</h2>
|
||||
</div>
|
||||
<p>Reaching new users means supporting an increasing variety of Android
|
||||
platform versions and device specifications. Optimize for common RAM and
|
||||
screen sizes and resolutions to improve the user experience. </p>
|
||||
|
||||
<h3 id="screens">Support varying screen sizes</h3>
|
||||
<h4 id="screens-dp">Use density-independent pixels (dp)</h4>
|
||||
<ul>
|
||||
<li>Defining layout dimensions with pixels is a problem because different
|
||||
screens have different pixel densities, so the same number of pixels may
|
||||
correspond to different physical sizes on different devices. The
|
||||
density-independent pixel (dp) corresponds to the physical size of a pixel
|
||||
at 160 dots per inch (mdpi density).</li>
|
||||
<li>Defining layouts with dp ensures that the physical size of your user
|
||||
interface is consistent regardless of device. Visit the Android
|
||||
guide on <a
|
||||
href="https://developer.android.com/guide/practices/screens_support.html">
|
||||
Supporting Multiple Screens</a> for best practices using
|
||||
density-independent pixels.</li>
|
||||
</ul>
|
||||
<h4 id="screens-density">Test graphics on ldpi/mdpi screen densities</h4>
|
||||
<ul>
|
||||
<li>Ensure that your app layouts work well on low- and medium-density
|
||||
(ldpi/mdpi) screens because these are <a
|
||||
href="https://developer.android.com/about/dashboards/index.html#Screens">
|
||||
common densities</a>, especially in lower-cost devices. Testing on
|
||||
lower-density screens helps to validate that your layouts are legible on
|
||||
lower-density screens.</li>
|
||||
<li>Lower-density screens can result in unclear text where the finer details
|
||||
aren't visible. The Material Design guidelines describe <a
|
||||
class="external-link" href="https://www.google.com/design/spec/layout/metrics-keylines.html">
|
||||
metrics and keylines</a> to ensure that your layouts can scale across
|
||||
screen densities.</li>
|
||||
<li>Devices with lower-density screens tend to have lower hardware
|
||||
specifications. To ensure that your app performs well on these devices,
|
||||
consider reducing or eliminating heavy loads, such as animations and
|
||||
transitions. For more information on supporting different densities, see
|
||||
the Android training on <a
|
||||
href="https://developer.android.com/training/multiscreen/screendensities.html">
|
||||
Supporting Different Densities</a>.</li>
|
||||
</ul>
|
||||
<h4 id="screens-sizes">Test layouts on small/medium screen sizes</h4>
|
||||
<ul>
|
||||
<li>Validate that your layouts scale down by testing on smaller screens. As
|
||||
screen sizes shrink, be very selective about visible UI elements, because
|
||||
there is limited space for them.</li>
|
||||
<li>Devices with smaller screens tend to have lower hardware specifications.
|
||||
To ensure that your app performs well on these devices, try reducing or
|
||||
eliminating heavy loads, such as animations or transitions. For more
|
||||
information on supporting different screen sizes, see the Android
|
||||
training on <a
|
||||
href="https://developer.android.com/training/multiscreen/screendensities.html">
|
||||
Supporting Different Screen Sizes</a>.</li>
|
||||
</ul>
|
||||
|
||||
<h3 id="compatibility">Backward compatibility</h3>
|
||||
<h4 id="compatibility-sdkversion">Set your targetSdkVersion and minSdkVersion
|
||||
appropriately</h4>
|
||||
<ul>
|
||||
<li>Apps should build and target a recent version of Android to ensure most
|
||||
current behavior across a broad range of devices; this still provides
|
||||
backward compatibility to older versions. Here are the best practices for
|
||||
targeting API levels appropriately:
|
||||
<ul>
|
||||
<li><a
|
||||
href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#target">
|
||||
{@code targetSdkVersion}</a> should be the latest version of Android.
|
||||
Targeting the most recent version ensures that your app inherits newer
|
||||
runtime behaviors when running newer versions of Android. Be sure to
|
||||
test your app on newer Android versions when updating the
|
||||
targetSdkVersion as it can affect app behavior.</li>
|
||||
<li><a
|
||||
href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#min">
|
||||
{@code minSdkVersion}</a> sets the minimum supported Android version.
|
||||
Use Android 4.0 (API level 14: Ice Cream Sandwich) or Android 4.1 (API
|
||||
level 16: Jelly Bean)—these versions give maximum coverage for modern
|
||||
devices. Setting {@code minSdkVersion} also results in the Android build
|
||||
tools reporting incorrect use of new APIs that might not be available in
|
||||
older versions of the platform. By doing so, developers are protected
|
||||
from inadvertently breaking backward compatibility.</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>Consult the <a
|
||||
href="https://developer.android.com/about/dashboards/index.html#Platform">
|
||||
Android dashboards</a>, the <a class="external-link"
|
||||
href="https://play.google.com/apps/publish/">Google Play Developer
|
||||
Console</a> for your app, and industry research in your target markets to
|
||||
gauge which versions of Android to target, based on your target users.</li>
|
||||
</ul>
|
||||
<h4 id="compatibility-libraries">Use the Android Support libraries</h4>
|
||||
<ul>
|
||||
<li>Ensure your app provides a consistent experience across OS versions by
|
||||
using the Google-provided support libraries such as AppCompat and the Design
|
||||
Support Library. The Android Support Library package is a set of code
|
||||
libraries that provides backward-compatible versions of Android framework
|
||||
APIs as well as features that are only available through the library APIs.
|
||||
</li>
|
||||
<li>Some of the the highlights include:
|
||||
<ul>
|
||||
<li>v4 & v7 support library: Many framework APIs for older versions of
|
||||
Android such as {@link android.support.v4.view.ViewPager},
|
||||
{@link android.app.ActionBar},
|
||||
{@link android.support.v7.widget.RecyclerView}, and
|
||||
{@link android.support.v7.graphics.Palette}.</li>
|
||||
<li><a href="{@docRoot}tools/support-library/features.html#design">Design
|
||||
Support</a> library: APIs to support adding Material Design components
|
||||
and patterns to your apps.</li>
|
||||
<li><a href="{@docRoot}tools/support-library/features.html#multidex">
|
||||
Multidex Support</a> library: provides support for large apps that have
|
||||
more than 65K methods. This can happen if your app is using many
|
||||
libraries.</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>For more information on the available support libraries, see the <a
|
||||
href="https://developer.android.com/tools/support-library/features.html">
|
||||
Support Libraries Features</a> section of the Android Developer site.</li>
|
||||
</ul>
|
||||
<h4 id="compatibility-playservices">Use Google Play services</h4>
|
||||
<ul>
|
||||
<li>Google Play services brings the best of Google APIs independent of
|
||||
Android platform version. Consider using features from Google Play services
|
||||
to offer the most streamlined Google experience on Android devices.</li>
|
||||
<li>Google Play services also include useful APIs such as <a
|
||||
href="https://developers.google.com/android/reference/com/google/android/gms/gcm/GcmNetworkManager">
|
||||
<code>GcmNetworkManager</code></a>, which provides much of Android 5.0’s
|
||||
{@link android.app.job.JobScheduler} API for older versions of Android. </li>
|
||||
<li>Updates to Google Play services are distributed automatically by the
|
||||
Google Play Store, and new versions of the client library are delivered
|
||||
through the Android SDK Manager. </li>
|
||||
</ul>
|
||||
<h3 id="memory">Efficient memory usage</h3>
|
||||
<h4 id="memory-footprint">Reduce memory footprint on low-cost devices</h4>
|
||||
<ul>
|
||||
<li>Adjusting your memory footprint dynamically helps to ensure compatibility
|
||||
across devices with different RAM configurations.</li>
|
||||
<li>Methods such as {@link android.app.ActivityManager#isLowRamDevice} and
|
||||
{@link android.app.ActivityManager#getMemoryClass()} help determine memory
|
||||
constraints at runtime. Based on this information, you can scale down your
|
||||
memory usage. As an example, you can use lower resolution images on low memory
|
||||
devices.</li>
|
||||
<li>For more information on managing your app’s memory, see the Android
|
||||
training on <a href="{@docRoot}training/articles/memory.html">Managing
|
||||
Your App's Memory</a>.</li>
|
||||
</ul>
|
||||
<h4 id="memory-longprocesses">Avoid long-running processes</h4>
|
||||
<ul>
|
||||
<li>Long-running processes stay resident in memory and can result in slowing
|
||||
down the device. In most situations, your app should wake up for a given
|
||||
event, process data, and shut down. You should use <a
|
||||
href="https://developers.google.com/cloud-messaging">Google Cloud Messaging
|
||||
(GCM)</a> and/or <a
|
||||
href="https://developers.google.com/android/reference/com/google/android/gms/gcm/GcmNetworkManager">
|
||||
<code>GcmNetworkManager</code></a> to avoid long running background
|
||||
services and reduce memory pressure on the user’s device.</li>
|
||||
</ul>
|
||||
<h4 id="memory-benchmark">Benchmark memory usage</h4>
|
||||
<ul>
|
||||
<li>Android Studio provides memory benchmarking and profiling tools, enabling
|
||||
you to measure memory usage at run time. Benchmarking your app’s memory
|
||||
footprint enables you to monitor memory usage over multiple versions of
|
||||
the app. This can help catch unintentional memory footprint growth. These
|
||||
tools can be used in the following ways:
|
||||
<ul>
|
||||
<li>Use the <a
|
||||
href="{@docRoot}tools/performance/memory-monitor/index.html">Memory
|
||||
Monitor</a> tool to find out whether undesirable garbage collection (GC)
|
||||
event patterns might be causing performance problems.</li>
|
||||
<li>Run <a
|
||||
href="{@docRoot}tools/performance/heap-viewer/index.html">Heap Viewer</a>
|
||||
to identify object types that get or stay allocated unexpectedly or
|
||||
unnecessarily.</li>
|
||||
<li>Use <a
|
||||
href="{@docRoot}tools/performance/allocation-tracker/index.html">
|
||||
Allocation Tracker</a> to identify where in your code the problem might
|
||||
be.</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>For more information on benchmarking memory usage, see the <a
|
||||
href="{@docRoot}tools/performance/comparison.html">
|
||||
Memory Profilers</a> tools on the Android Developers site.</li>
|
||||
</ul>
|
||||
|
||||
<h3 class="rel-resources clearfloat">Related resources</h3>
|
||||
<div class="resource-widget resource-flow-layout col-13"
|
||||
data-query="collection:distribute/essentials/billionsquality/capability"
|
||||
data-sortOrder="-timestamp"
|
||||
data-cardSizes="6x3"
|
||||
data-maxResults="6"></div>
|
||||
|
||||
<!-- cost -->
|
||||
<div class="headerLine">
|
||||
<h2 id="cost">Data Cost</h2>
|
||||
</div>
|
||||
<p>Data plans in some countries can cost upwards of 10% of monthly income.
|
||||
Conserve data and give control to optimize user experience. Reduce data
|
||||
consumption and give users control over your app’s use of data.</p>
|
||||
|
||||
<h3 id="appsize">Reduce app size</h3>
|
||||
<h4 id="appsize-graphics">Reduce APK graphical asset size</h4>
|
||||
<ul>
|
||||
<li>Graphical assets are often the largest contributor to the size of the
|
||||
APK. Optimizing these can result in smaller downloads and thus faster
|
||||
installation times for users.</li>
|
||||
<li>For graphical assets like icons, use Scalable Vector Graphics (SVG)
|
||||
format. SVG images are relatively tiny in size and can be rendered at
|
||||
runtime to any resolution. The <a
|
||||
href="{@docRoot}tools/support-library/index.html">Android Support</a>
|
||||
library provides a backward-compatible implementation for vector resources as
|
||||
far back as Android 2.1 (API level 7). Get started with vectors with <a
|
||||
class="external-link"
|
||||
href="https://medium.com/@chrisbanes/appcompat-v23-2-age-of-the-vectors-91cbafa87c88">
|
||||
this Medium post</a>. </li>
|
||||
<li>For non-vector images, like photos, use <a
|
||||
href="https://developers.google.com/speed/webp/">WebP</a>. WebP reduces
|
||||
image load times, saves network bandwidth, and is proven to result in
|
||||
smaller file sizes than its PNG and JPG counterparts, with at least the
|
||||
same image quality. Even at lossy settings, WebP can produce a nearly
|
||||
identical image. Android has had lossy WebP support since Android 4.0 (API
|
||||
level 14: Ice Cream Sandwich) and support for lossless / transparent WebP since Android 4.2 (API level 17: Jelly Bean).</li>
|
||||
<li>If you have many large images across multiple densities, consider
|
||||
using <a href="{@docRoot}google/play/publishing/multiple-apks.html">Multiple
|
||||
APK support</a> to split your APK by density. This results in builds
|
||||
targeted for specific densities, meaning users with low-density devices
|
||||
won’t have to incur the penalty of unused high-density assets.</li>
|
||||
<li>A detailed guide on reducing your APK size can be found in <a
|
||||
class="external-link" href="https://medium.com/@wkalicinski/smallerapk-part-4-multi-apk-through-abi-and-density-splits-477083989006">
|
||||
series of Medium posts</a>.</li>
|
||||
</ul>
|
||||
<h4 id="appsize-code">Reduce code size</h4>
|
||||
<ul>
|
||||
<li>Be careful about using external libraries because not all libraries are
|
||||
meant to be used in mobile apps. Ensure that the libraries your app is
|
||||
using are optimized for mobile use.</li>
|
||||
<li>Every library in your Android project is adding potentially unused code
|
||||
to your APK. There are also some libraries that aren’t designed with mobile
|
||||
development in mind. These libraries can end up contributing to significant
|
||||
APK bloat.</li>
|
||||
<li>Consider optimizing your compiled code using a tool such as <a
|
||||
href="{@docRoot}tools/help/proguard.html">ProGuard</a>. ProGuard identifies
|
||||
code that isn’t being used and removes it from your APK. Also <a
|
||||
class="external-link"
|
||||
href="http://tools.android.com/tech-docs/new-build-system/resource-shrinking">
|
||||
enable resource shrinking</a> at build time by setting
|
||||
<code>minifyEnabled=true</code>, <code>shrinkResources=true</code> in
|
||||
<code>build.gradle</code>—this automatically removes unused resources from
|
||||
your APK.</li>
|
||||
<li>When using Google Play services, you should <a
|
||||
href="{@docRoot}google/play-services/setup.html#add_google_play_services_to_your_project">
|
||||
selectively include</a> only the necessary APIs into your APK.</li>
|
||||
<li>For more information on reducing code size in your APK, see the Android
|
||||
training on how to <a
|
||||
href="{@docRoot}training/articles/memory.html#DependencyInjection">Avoid
|
||||
dependency injection frameworks</a>.</li>
|
||||
</ul>
|
||||
<h4 id="appsize-external">Allow app to be moved to external (SD) storage</h4>
|
||||
<ul>
|
||||
<li>Low-cost devices often come with little on-device storage. Users can
|
||||
extend this with SD cards; however, apps need to explicitly declare that
|
||||
they support being installed to external storage before users can move them.
|
||||
</li>
|
||||
<li>Allow your app to be installed to external storage using the <a
|
||||
href="{@docRoot}guide/topics/manifest/manifest-element.html#install"><code>
|
||||
android:installLocation</code></a> flag in your AndroidManifest. For more
|
||||
information on enabling your app to be moved to external storage, see the
|
||||
Android guide on <a
|
||||
href="{@docRoot}guide/topics/data/install-location.html">App Install
|
||||
Location</a>.</li>
|
||||
</ul>
|
||||
|
||||
<h4 id="appsize-postinstall">Reduce post-install app disk usage</h4>
|
||||
<ul>
|
||||
<li>Keeping your app’s disk usage low means that users are less likely to
|
||||
uninstall your app when the device is low on free space. When using caches,
|
||||
it’s important to apply bounds around your caches—this prevents your app’s
|
||||
disk usage from growing indefinitely. Be sure you put your cached data in
|
||||
{@link android.content.Context#getCacheDir()}—the system can delete files
|
||||
placed here as needed, so they won’t show up as storage committed to the
|
||||
app.</li>
|
||||
</ul>
|
||||
|
||||
<h3 id="configurablenetwork">Offer configurable network usage</h3>
|
||||
<h4 id="configurablenetwork-onboarding">Provide onboarding experiences for
|
||||
subjective user choices</h4>
|
||||
<ul>
|
||||
<li>Apps that allow users to reduce data usage are well received, even if
|
||||
they demand heavy data requirements. If your app uses a considerable amount
|
||||
of bandwidth (for example, video streaming apps), you can provide an
|
||||
onboarding experience for users to configure network usage. For example,
|
||||
you could allow the user to force lower-bitrate video streams on cellular
|
||||
networks. </li>
|
||||
<li>Additional settings for users to control data syncing, prefetching, and
|
||||
network usage behavior (for example, prefetch all starred news categories on
|
||||
Wi-Fi only), also help users tailor your app’s behavior to their needs.</li>
|
||||
<li>For more information on managing network usage, see the Android training
|
||||
on <a href="{@docRoot}training/basics/network-ops/managing.html">Managing
|
||||
Network Usage</a>.</li>
|
||||
</ul>
|
||||
<h4 id="configurablenetwork-preferences">Provide a network preferences
|
||||
screen</h4>
|
||||
<ul>
|
||||
<li>You can navigate to the app’s network settings from outside the app by
|
||||
means of a network preferences screen. You can invoke this screen from
|
||||
either the system settings screen or the system data usage screen.</li>
|
||||
<li>To provide a network preferences screen that users can access from within
|
||||
your app as well as from the system settings, in your app include an
|
||||
activity that supports the
|
||||
{@link android.content.Intent#ACTION_MANAGE_NETWORK_USAGE} action.</li>
|
||||
<li>For further information on adding a network preferences screen, see the
|
||||
Android training on <a
|
||||
href="{@docRoot}training/basics/network-ops/managing.html#prefs">
|
||||
Implementing a Preferences Activity</a>.</li>
|
||||
</ul>
|
||||
|
||||
<!-- consumption -->
|
||||
<div class="headerLine">
|
||||
<h2 id="consumption">Battery Consumption</h2>
|
||||
</div>
|
||||
<p>Access to reliable power supplies varies, and outages can disrupt planned
|
||||
charges. Defend your users' batteries against unnecessary drain by benchmarking
|
||||
your battery use, avoiding wakelocks, scheduling tasks, and monitoring sensor
|
||||
requests.</p>
|
||||
<h3 id="consumption-reduce">Reduce battery consumption</h3>
|
||||
<ul>
|
||||
<li>Your app should do minimal activity when in the background and when the
|
||||
device is running on battery power.</li>
|
||||
<li><a href="{@docRoot}reference/android/os/PowerManager.WakeLock.html">Wake
|
||||
locks</a> are mechanisms to keep devices on so that they can perform
|
||||
background activities. Avoid using wake locks because they prevent the
|
||||
device from going into low-power states.</li>
|
||||
<li>To reduce the number of device wake-ups, batch network activity. For more
|
||||
information on batching, see the Android training on <a
|
||||
href="{@docRoot}training/efficient-downloads/efficient-network-access.html">
|
||||
Optimizing Downloads for Efficient Network Access</a>.</li>
|
||||
<li><a
|
||||
href="https://developers.google.com/android/reference/com/google/android/gms/gcm/GcmNetworkManager">
|
||||
<code>GcmNetworkManager</code></a> schedules tasks and lets Google Play
|
||||
services batch operations across the system. This greatly
|
||||
simplifies the implementation of common patterns, such as waiting for
|
||||
network connectivity, device charging state, retries, and backoff. Use
|
||||
<code>GcmNetworkManager</code> to perform non-essential background activity
|
||||
when the device is charging and is connected to an unmetered network.</li>
|
||||
<li>Sensors, like GPS, can also have a significant drain on the battery. The
|
||||
recommended way to request location is to use the FusedLocationProvider API.
|
||||
The <a
|
||||
href="https://developers.google.com/android/reference/com/google/android/gms/location/FusedLocationProviderApi">FusedLocationProvider</a> API manages the
|
||||
underlying location technology and provides a simple API so that you can
|
||||
specify requirements—like high accuracy or low power—at a high
|
||||
level. It also optimizes the device's use of battery power by caching
|
||||
locations and batching requests across apps. For more information on the
|
||||
ideal ways to request location, see the <a
|
||||
href="{@docRoot}training/location/retrieve-current.html">Getting the Last
|
||||
Known Location</a> training guide.
|
||||
</li>
|
||||
</ul>
|
||||
<h3 id="consumption-benchmark">Benchmark battery usage</h3>
|
||||
<ul>
|
||||
<li>Benchmarking your app’s usage in a controlled environment helps you
|
||||
understand the battery-heavy tasks in your app. It is a good practice to
|
||||
benchmark your app’s battery usage to gauge efficiency and track changes
|
||||
over time.
|
||||
</li>
|
||||
<li><a
|
||||
href="{@docRoot}tools/performance/batterystats-battery-historian/index.html">
|
||||
Batterystats</a> collects battery data about your apps, and <a
|
||||
href="{@docRoot}tools/performance/batterystats-battery-historian/index.html">
|
||||
Battery Historian</a> converts that data into an HTML visualization. For
|
||||
more information on reducing battery usage, see the Android training on <a
|
||||
href="{@docRoot}training/monitoring-device-state/index.html">Optimizing
|
||||
Battery Life</a>.</li>
|
||||
</ul>
|
||||
|
||||
<h3 class="rel-resources clearfloat">Related resources</h3>
|
||||
<div class="resource-widget resource-flow-layout col-13"
|
||||
data-query="collection:distribute/essentials/billionsquality/consumption"
|
||||
data-sortOrder="-timestamp"
|
||||
data-cardSizes="6x3"
|
||||
data-maxResults="6"></div>
|
||||
|
||||
<!-- content -->
|
||||
<div class="headerLine">
|
||||
<h2 id="contentsection">Content</h2>
|
||||
</div>
|
||||
<p>Make sure that your app works well on a variety of screens: offering good,
|
||||
crisp graphics and appropriate layouts on low resolution and physically small
|
||||
screens. Ensure that your app is designed to be easily localized by
|
||||
accommodating the variations between languages: allow for spacing, density,
|
||||
order, emphasis, and wording variations. Also make sure that date, time, and
|
||||
the like are internationalized and displayed according to the phone’s
|
||||
settings.</p>
|
||||
|
||||
<h3 id="content-responsive">Fast and responsive UI</h3>
|
||||
<h4 id="content-feedback">Touch feedback on all touchable items</h4>
|
||||
<ul>
|
||||
<li>Touch feedback adds a tactile feeling to the user interface. You should
|
||||
ensure your app provides touch feedback on all touchable elements to reduce
|
||||
the perceived app latency as much as possible.
|
||||
</li>
|
||||
<li><a
|
||||
href="https://www.google.com/design/spec/animation/responsive-interaction.html">
|
||||
Responsive interaction</a> encourages deeper exploration of an app by
|
||||
creating timely, logical, and delightful screen reactions to user input.
|
||||
Responsive interaction elevates an app from an information-delivery service
|
||||
to an experience that communicates using multiple visual and tactile
|
||||
responses.</li>
|
||||
<li>For more information, see the Android training on <a
|
||||
href="{@docRoot}training/material/animations.html#Touch">Customizing Touch
|
||||
Feedback</a>.</li>
|
||||
</ul>
|
||||
<h4 id="content-interactive">UI should always be interactive</h4>
|
||||
<ul>
|
||||
<li>Apps that are unresponsive when performing background activity feel slow
|
||||
and reduce user satisfaction. Ensure your app always has a responsive UI
|
||||
regardless of any background activity. Achieve this by performing network
|
||||
operations or any heavy-duty operations in a background thread—keep the UI
|
||||
thread as idle as you can.</li>
|
||||
<li>Material Design apps use minimal visual changes when your app is loading
|
||||
content by representing each operation with a single activity indicator.
|
||||
Avoid blocking dialogs with <a
|
||||
href="https://www.google.com/design/spec/components/progress-activity.html">
|
||||
loading indicators</a>.</li>
|
||||
<li><a
|
||||
href="http://www.google.com/design/spec/patterns/empty-states.html">Empty
|
||||
states</a> occur when the regular content of a view can’t be shown. It might
|
||||
be a list that has no items or a search that returns no results. Avoid
|
||||
completely empty states. The most basic empty state displays a
|
||||
non-interactive image and a text tagline. Where you don’t have an image, or
|
||||
the image is still loading, you should always show either a static
|
||||
placeholder, or create a dynamic placeholder by using the <a
|
||||
href="{@docRoot}tools/support-library/features.html#v7-palette">Palette
|
||||
library</a> to generate placeholder colors that match the target image.</li>
|
||||
<li>For more information, see the Android training on <a
|
||||
href="{@docRoot}training/articles/perf-anr.html">Keeping Your App
|
||||
Responsive</a>.</li>
|
||||
</ul>
|
||||
<h4 id="content-60fps">Target 60 frames per second on low-cost devices</h4>
|
||||
<ul>
|
||||
<li>Ensure that your app always runs fast and smoothly, even on low-cost
|
||||
devices.</li>
|
||||
<li>Overdraw can significantly slow down your app—it occurs when the pixels
|
||||
are being drawn more than once per pass. An example of this is when you have
|
||||
an image with a button placed on top of it. While some overdraw is
|
||||
unavoidable, it should be minimized to ensure a smooth frame rate. Perform
|
||||
<a href="{@docRoot}tools/performance/debug-gpu-overdraw/index.html">Debug
|
||||
GPU overdraw</a> on your app to ensure it is minimized.</li>
|
||||
<li>Android devices refresh the screen at 60 frames per second (fps), meaning
|
||||
your app has to update the screen within roughly 16 milliseconds. <a
|
||||
href="{@docRoot}tools/performance/profile-gpu-rendering/index.html">Profile
|
||||
your app</a> using on-device tools to see if and when your app is not
|
||||
meeting this 16-ms average.</li>
|
||||
<li>Reduce or remove animations on low-cost devices to lessen the burden on
|
||||
the device’s CPU and GPU. For more information, see the Android training on
|
||||
<a href="{@docRoot}training/improving-layouts/index.html">Improving Layout
|
||||
Performance</a>. </li>
|
||||
</ul>
|
||||
<h4 id="content-firstload">If anticipated start speed is low, use launch screen
|
||||
on first load</h4>
|
||||
<ul>
|
||||
<li>The launch screen is a user’s first experience of your application.
|
||||
Launching your app while displaying a blank canvas increases its perceived
|
||||
loading time, so consider using a placeholder UI or a branded launch screen
|
||||
to reduce the perceived loading time.</li>
|
||||
<li>A<a href="https://www.google.com/design/spec/patterns/launch-screens.html#launch-screens-types-of-launch-screens">
|
||||
placeholder UI</a> is the most seamless launch transition, appropriate for
|
||||
both app launches and in-app activity transitions.</li>
|
||||
<li><a
|
||||
href="https://www.google.com/design/spec/patterns/launch-screens.html#launch-screens-placeholder-ui">
|
||||
Branded launch screens</a> provide momentary brand exposure, freeing the UI
|
||||
to focus on content.</li>
|
||||
<li>For more information on implementing splash screens, see the <a
|
||||
href="https://www.google.com/design/spec/patterns/launch-screens.html">
|
||||
Launch screens</a> section of the Material Design spec.</li>
|
||||
</ul>
|
||||
<h3 id="ui">UI best practices</h3>
|
||||
<ul>
|
||||
<li><a
|
||||
href="https://www.google.com/design/spec/material-design/introduction.html">
|
||||
Material Design</a> is a visual language that synthesizes the classic
|
||||
principles of good design with the innovation and possibility of technology
|
||||
and science. Material Design aims to develop a single underlying system that
|
||||
allows for a unified experience across platforms and device sizes. Consider
|
||||
using key Material Design components so that users intuitively know how to
|
||||
use your app.</li>
|
||||
<li>Ready-to-use Material Design components are available via the <a
|
||||
href="{@docRoot}tools/support-library/features.html#design">Design Support
|
||||
library</a>. These components are supported in Android 2.1 (API level 7) and
|
||||
above.</li>
|
||||
</ul>
|
||||
<h3 id="localization">Localization</h3>
|
||||
<ul>
|
||||
<li>Your users could be from any part of the world and their first language
|
||||
may not be yours. If you don’t present your app in a language that your
|
||||
users can read, it is a missed opportunity. You should therefore
|
||||
localize your app for key regional languages.</li>
|
||||
<li>To learn more, visit the Android training on <a
|
||||
href="{@docRoot}training/basics/supporting-devices/languages.html">
|
||||
Supporting Different Languages</a>.</li>
|
||||
</ul>
|
||||
|
||||
<h3 class="rel-resources clearfloat">Related resources</h3>
|
||||
<div class="resource-widget resource-flow-layout col-13"
|
||||
data-query="collection:distribute/essentials/billionsquality/content"
|
||||
data-sortOrder="-timestamp"
|
||||
data-cardSizes="6x3"
|
||||
data-maxResults="6"></div>
|
||||
BIN
docs/html/distribute/images/billions-guidelines.png
Normal file
BIN
docs/html/distribute/images/billions-guidelines.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 951 B |
@@ -276,6 +276,18 @@ METADATA['en'].extras = METADATA['en'].extras.concat([
|
||||
"image":"https://cdn-images-1.medium.com/max/2000/1*chMiA9mGa_FBUOoesHHk3Q.png",
|
||||
"type":"medium"
|
||||
},
|
||||
{
|
||||
"title":"SmallerAPK, Part 6: Image optimization, Zopfli & WebP",
|
||||
"category":"",
|
||||
"summary":"Series of posts on minimizing your APK size.",
|
||||
"url":"https://medium.com/@wkalicinski/smallerapk-part-6-image-optimization-zopfli-webp-4c462955647d#.23hlddo3x",
|
||||
"group":"",
|
||||
"keywords": [],
|
||||
"tags": [],
|
||||
"image":"https://cdn-images-1.medium.com/max/2000/1*chMiA9mGa_FBUOoesHHk3Q.png",
|
||||
"type":"medium"
|
||||
},
|
||||
|
||||
{
|
||||
"title":"Measure your app’s user acquisition channels",
|
||||
"category":"google",
|
||||
@@ -1158,6 +1170,20 @@ METADATA['en'].extras = METADATA['en'].extras.concat([
|
||||
"type": "develop",
|
||||
"category": "compatibility"
|
||||
},
|
||||
{
|
||||
"lang": "en",
|
||||
"group": "",
|
||||
"tags": [],
|
||||
"url": "training/material/animations.html#Touch",
|
||||
"timestamp": 1194884220000,
|
||||
"image": null,
|
||||
"title": "Customize Touch Feedback",
|
||||
"summary": "Provide visual confirmation when users interact with your UI.",
|
||||
"keywords": [],
|
||||
"type": "develop",
|
||||
"category": "guide"
|
||||
},
|
||||
|
||||
{
|
||||
"lang": "en",
|
||||
"group": "",
|
||||
@@ -3825,6 +3851,7 @@ METADATA['en'].collections = {
|
||||
"distribute/essentials/quality/tv.html",
|
||||
"distribute/essentials/quality/wear.html",
|
||||
"distribute/essentials/quality/auto.html",
|
||||
"distribute/essentials/quality/billions.html",
|
||||
"https://developers.google.com/edu/guidelines"
|
||||
]
|
||||
},
|
||||
@@ -3946,6 +3973,7 @@ METADATA['en'].collections = {
|
||||
"distribute/essentials/quality/wear.html",
|
||||
"distribute/essentials/quality/tv.html",
|
||||
"distribute/essentials/quality/auto.html",
|
||||
"distribute/essentials/quality/billions.html",
|
||||
"https://developers.google.com/edu/guidelines"
|
||||
]
|
||||
},
|
||||
@@ -4403,6 +4431,44 @@ METADATA['en'].collections = {
|
||||
"distribute/tools/promote/device-art.html"
|
||||
]
|
||||
},
|
||||
"distribute/essentials/billionsquality/connectivity": {
|
||||
"title": "",
|
||||
"resources": [
|
||||
"training/basics/network-ops/managing.html",
|
||||
"training/monitoring-device-state/connectivity-monitoring.html",
|
||||
"guide/topics/providers/content-providers.html"
|
||||
]
|
||||
},
|
||||
"distribute/essentials/billionsquality/capability": {
|
||||
"title": "",
|
||||
"resources": [
|
||||
"guide/practices/screens_support.html",
|
||||
"training/multiscreen/screendensities.html",
|
||||
"training/articles/memory.html"
|
||||
]
|
||||
},
|
||||
"distribute/essentials/billionsquality/cost": {
|
||||
"title": "",
|
||||
"resources": [
|
||||
"https://medium.com/@wkalicinski/smallerapk-part-4-multi-apk-through-abi-and-density-splits-477083989006#.23hlddo3x",
|
||||
"training/basics/network-ops/managing.html"
|
||||
]
|
||||
},
|
||||
"distribute/essentials/billionsquality/consumption": {
|
||||
"title": "",
|
||||
"resources": [
|
||||
"training/efficient-downloads/efficient-network-access.html",
|
||||
"training/monitoring-device-state/index.html"
|
||||
]
|
||||
},
|
||||
"distribute/essentials/billionsquality/content": {
|
||||
"title": "",
|
||||
"resources": [
|
||||
"training/material/animations.html#Touch",
|
||||
"training/articles/perf-anr.html",
|
||||
"training/improving-layouts/index.html"
|
||||
]
|
||||
},
|
||||
"distribute/getusers/notifications": {
|
||||
"title": "",
|
||||
"resources": [
|
||||
|
||||
Reference in New Issue
Block a user