[转]Android内存和性能优化 - 教程

Android内存和性能优化。本教程介绍如何优化内存使用情况并优化Android应用程序的性能。本教程基于Android Studio。

1.提供高响应和快速Android应用程序的编程技巧

1.1。为什么要小心使用Android资源

Android设备的功耗低于标准台式机或笔记本电脑。因此,您必须小心内存消耗。

特别是在Android 5.0之前的Android设备上,您希望避免触发Java虚拟机的垃圾收集器。这会导致Android运行时冻结约200毫秒。如果用户例如向下滚动列表,则这可能是显着的延迟。

1.2。避免不必要的对象分配

避免创建不必要的物体,尤其是在昂贵的地方 尽可能重用对象。创建不必要的对象会更频繁地触发垃圾回收,这应该避免。

例如,避免在循环或onDraw()自定义视图的方法中创建对象。

1.3。使用高效的数据结构

Android提供了几种Sparse*Array 类的实现。请考虑以下代码。

<span style="color:rgba(0, 0, 0, 0.8)"><span style="color:#faf6e4"><code>Map<span style="color:#4df4ff"><strong><</strong></span>Integer<span style="color:#4df4ff"><strong>,</strong></span> String<span style="color:#4df4ff"><strong>></strong></span> map <span style="color:#4df4ff"><strong>=</strong></span> <span style="color:#f6dd62"><strong>new</strong></span> HashMap<span style="color:#4df4ff"><strong><</strong></span>Integer<span style="color:#4df4ff"><strong>,</strong></span> String<span style="color:#4df4ff"><strong>>();</strong></span></code></span></span>

使用此代码会导致Integer创建不必要的对象。

Android提供的数据结构更有效地将值映射到其他对象。如果可能的话,使用这些对象,就像使用HashMap一样,它们避免了对象的创建。对象创建可能很昂贵,应该避免以减少垃圾收集器运行所需的次数。

该表给出了SparseArrays的示例。

表1.高效的内存结构
记忆结构 描述

SparseArray <E>

将整数映射到对象,避免创建Integer对象。

SparseBooleanArray

将整数映射到布尔值。

SparseIntArray

将整数映射到整数

要改进上面的示例,请使用以下数据结构。

<span style="color:rgba(0, 0, 0, 0.8)"><span style="color:#faf6e4"><code>SparseArray<span style="color:#4df4ff"><strong><</strong></span>String<span style="color:#4df4ff"><strong>></strong></span> map <span style="color:#4df4ff"><strong>=</strong></span> <span style="color:#f6dd62"><strong>new</strong></span> SparseArray<span style="color:#4df4ff"><strong><</strong></span>String<span style="color:#4df4ff"><strong>>();</strong></span>
map<span style="color:#4df4ff"><strong>.</strong></span><span style="color:#a8e1fe">put</span><span style="color:#4df4ff"><strong>(</strong></span><span style="color:#f696db"><strong>1</strong></span><span style="color:#4df4ff"><strong>,</strong></span> <span style="color:#fff0a6"><strong>"Hello"</strong></span><span style="color:#4df4ff"><strong>);</strong></span></code></span></span>

2.处理位图

如果以全尺寸加载,位图可以分配大量内存。建议将所需大小的位图加载到内存中。假设您有一个以100x100 dp显示图像的应用程序,您应该以这个大小加载图像。

一种常见的方法是首先测量位图,而不是通过传递给它的标志加载它 BitmapFactory

<span style="color:rgba(0, 0, 0, 0.8)"><span style="color:#faf6e4"><code><span style="color:#6c8b9f"><em>// instruct BitmapFactory to only the bounds and type of the image</em></span>
BitmapFactory<span style="color:#4df4ff"><strong>.</strong></span><span style="color:#a8e1fe">Options</span> options <span style="color:#4df4ff"><strong>=</strong></span> <span style="color:#f6dd62"><strong>new</strong></span> BitmapFactory<span style="color:#4df4ff"><strong>.</strong></span><span style="color:#a8e1fe">Options</span><span style="color:#4df4ff"><strong>();</strong></span>
options<span style="color:#4df4ff"><strong>.</strong></span><span style="color:#a8e1fe">inJustDecodeBounds</span> <span style="color:#4df4ff"><strong>=</strong></span> <span style="color:#f696db"><strong>true</strong></span><span style="color:#4df4ff"><strong>;</strong></span>
BitmapFactory<span style="color:#4df4ff"><strong>.</strong></span><span style="color:#a8e1fe">decodeResource</span><span style="color:#4df4ff"><strong>(</strong></span>getResources<span style="color:#4df4ff"><strong>(),</strong></span> R<span style="color:#4df4ff"><strong>.</strong></span><span style="color:#a8e1fe">id</span><span style="color:#4df4ff"><strong>.</strong></span><span style="color:#a8e1fe">myimage</span><span style="color:#4df4ff"><strong>,</strong></span> options<span style="color:#4df4ff"><strong>);</strong></span>

<span style="color:#6c8b9f"><em>// get width and height</em></span>
<span style="color:#b2fd6d"><strong>int</strong></span> imageHeight <span style="color:#4df4ff"><strong>=</strong></span> options<span style="color:#4df4ff"><strong>.</strong></span><span style="color:#a8e1fe">outHeight</span><span style="color:#4df4ff"><strong>;</strong></span>
<span style="color:#b2fd6d"><strong>int</strong></span> imageWidth <span style="color:#4df4ff"><strong>=</strong></span> options<span style="color:#4df4ff"><strong>.</strong></span><span style="color:#a8e1fe">outWidth</span><span style="color:#4df4ff"><strong>;</strong></span>
<span style="color:#6c8b9f"><em>// type of the image</em></span>
String imageType <span style="color:#4df4ff"><strong>=</strong></span> options<span style="color:#4df4ff"><strong>.</strong></span><span style="color:#a8e1fe">outMimeType</span><span style="color:#4df4ff"><strong>;</strong></span></code></span></span>

之后,您可以加载图像的缩放版本。Android非常适合以2的幂来缩放图像。您可以使用以下方法(来自官方Android文档)以2为基础计算比例因子。

<span style="color:rgba(0, 0, 0, 0.8)"><span style="color:#faf6e4"><code><span style="color:#f6dd62"><strong>public</strong></span> <span style="color:#f6dd62"><strong>static</strong></span> Bitmap <span style="color:#a8e1fe">decodeBitmapWithGiveSizeFromResource</span><span style="color:#4df4ff"><strong>(</strong></span>Resources res<span style="color:#4df4ff"><strong>,</strong></span> <span style="color:#b2fd6d"><strong>int</strong></span> resId<span style="color:#4df4ff"><strong>,</strong></span>
        <span style="color:#b2fd6d"><strong>int</strong></span> reqWidth<span style="color:#4df4ff"><strong>,</strong></span> <span style="color:#b2fd6d"><strong>int</strong></span> reqHeight<span style="color:#4df4ff"><strong>)</strong></span> <span style="color:#4df4ff"><strong>{</strong></span>

    <span style="color:#6c8b9f"><em>// First decode with inJustDecodeBounds=true to check dimensions</em></span>
    <span style="color:#f6dd62"><strong>final</strong></span> BitmapFactory<span style="color:#4df4ff"><strong>.</strong></span><span style="color:#a8e1fe">Options</span> options <span style="color:#4df4ff"><strong>=</strong></span> <span style="color:#f6dd62"><strong>new</strong></span> BitmapFactory<span style="color:#4df4ff"><strong>.</strong></span><span style="color:#a8e1fe">Options</span><span style="color:#4df4ff"><strong>();</strong></span>
    options<span style="color:#4df4ff"><strong>.</strong></span><span style="color:#a8e1fe">inJustDecodeBounds</span> <span style="color:#4df4ff"><strong>=</strong></span> <span style="color:#f696db"><strong>true</strong></span><span style="color:#4df4ff"><strong>;</strong></span>
    BitmapFactory<span style="color:#4df4ff"><strong>.</strong></span><span style="color:#a8e1fe">decodeResource</span><span style="color:#4df4ff"><strong>(</strong></span>res<span style="color:#4df4ff"><strong>,</strong></span> resId<span style="color:#4df4ff"><strong>,</strong></span> options<span style="color:#4df4ff"><strong>);</strong></span>

    <span style="color:#6c8b9f"><em>// Calculate inSampleSize</em></span>
    options<span style="color:#4df4ff"><strong>.</strong></span><span style="color:#a8e1fe">inSampleSize</span> <span style="color:#4df4ff"><strong>=</strong></span> calculateInSampleSize<span style="color:#4df4ff"><strong>(</strong></span>options<span style="color:#4df4ff"><strong>,</strong></span> reqWidth<span style="color:#4df4ff"><strong>,</strong></span> reqHeight<span style="color:#4df4ff"><strong>);</strong></span>

    <span style="color:#6c8b9f"><em>// Decode bitmap with inSampleSize set</em></span>
    options<span style="color:#4df4ff"><strong>.</strong></span><span style="color:#a8e1fe">inJustDecodeBounds</span> <span style="color:#4df4ff"><strong>=</strong></span> <span style="color:#f696db"><strong>false</strong></span><span style="color:#4df4ff"><strong>;</strong></span>
    <span style="color:#f6dd62"><strong>return</strong></span> BitmapFactory<span style="color:#4df4ff"><strong>.</strong></span><span style="color:#a8e1fe">decodeResource</span><span style="color:#4df4ff"><strong>(</strong></span>res<span style="color:#4df4ff"><strong>,</strong></span> resId<span style="color:#4df4ff"><strong>,</strong></span> options<span style="color:#4df4ff"><strong>);</strong></span>
<span style="color:#4df4ff"><strong>}</strong></span>

<span style="color:#f6dd62"><strong>public</strong></span> <span style="color:#f6dd62"><strong>static</strong></span> <span style="color:#b2fd6d"><strong>int</strong></span> <span style="color:#a8e1fe">calculateInSampleSize</span><span style="color:#4df4ff"><strong>(</strong></span>
            BitmapFactory<span style="color:#4df4ff"><strong>.</strong></span><span style="color:#a8e1fe">Options</span> options<span style="color:#4df4ff"><strong>,</strong></span> <span style="color:#b2fd6d"><strong>int</strong></span> reqWidth<span style="color:#4df4ff"><strong>,</strong></span> <span style="color:#b2fd6d"><strong>int</strong></span> reqHeight<span style="color:#4df4ff"><strong>)</strong></span> <span style="color:#4df4ff"><strong>{</strong></span>
    <span style="color:#6c8b9f"><em>// Raw height and width of image</em></span>
    <span style="color:#f6dd62"><strong>final</strong></span> <span style="color:#b2fd6d"><strong>int</strong></span> height <span style="color:#4df4ff"><strong>=</strong></span> options<span style="color:#4df4ff"><strong>.</strong></span><span style="color:#a8e1fe">outHeight</span><span style="color:#4df4ff"><strong>;</strong></span>
    <span style="color:#f6dd62"><strong>final</strong></span> <span style="color:#b2fd6d"><strong>int</strong></span> width <span style="color:#4df4ff"><strong>=</strong></span> options<span style="color:#4df4ff"><strong>.</strong></span><span style="color:#a8e1fe">outWidth</span><span style="color:#4df4ff"><strong>;</strong></span>
    <span style="color:#b2fd6d"><strong>int</strong></span> inSampleSize <span style="color:#4df4ff"><strong>=</strong></span> <span style="color:#f696db"><strong>1</strong></span><span style="color:#4df4ff"><strong>;</strong></span>

    <span style="color:#f6dd62"><strong>if</strong></span> <span style="color:#4df4ff"><strong>(</strong></span>height <span style="color:#4df4ff"><strong>></strong></span> reqHeight <span style="color:#4df4ff"><strong>||</strong></span> width <span style="color:#4df4ff"><strong>></strong></span> reqWidth<span style="color:#4df4ff"><strong>)</strong></span> <span style="color:#4df4ff"><strong>{</strong></span>

        <span style="color:#f6dd62"><strong>final</strong></span> <span style="color:#b2fd6d"><strong>int</strong></span> halfHeight <span style="color:#4df4ff"><strong>=</strong></span> height <span style="color:#4df4ff"><strong>/</strong></span> <span style="color:#f696db"><strong>2</strong></span><span style="color:#4df4ff"><strong>;</strong></span>
        <span style="color:#f6dd62"><strong>final</strong></span> <span style="color:#b2fd6d"><strong>int</strong></span> halfWidth <span style="color:#4df4ff"><strong>=</strong></span> width <span style="color:#4df4ff"><strong>/</strong></span> <span style="color:#f696db"><strong>2</strong></span><span style="color:#4df4ff"><strong>;</strong></span>

        <span style="color:#6c8b9f"><em>// Calculate the largest inSampleSize value that is a power of 2 and keeps both</em></span>
        <span style="color:#6c8b9f"><em>// height and width larger than the requested height and width.</em></span>
        <span style="color:#f6dd62"><strong>while</strong></span> <span style="color:#4df4ff"><strong>((</strong></span>halfHeight <span style="color:#4df4ff"><strong>/</strong></span> inSampleSize<span style="color:#4df4ff"><strong>)</strong></span> <span style="color:#4df4ff"><strong>></strong></span> reqHeight
                <span style="color:#4df4ff"><strong>&&</strong></span> <span style="color:#4df4ff"><strong>(</strong></span>halfWidth <span style="color:#4df4ff"><strong>/</strong></span> inSampleSize<span style="color:#4df4ff"><strong>)</strong></span> <span style="color:#4df4ff"><strong>></strong></span> reqWidth<span style="color:#4df4ff"><strong>)</strong></span> <span style="color:#4df4ff"><strong>{</strong></span>
            inSampleSize <span style="color:#4df4ff"><strong>*=</strong></span> <span style="color:#f696db"><strong>2</strong></span><span style="color:#4df4ff"><strong>;</strong></span>
        <span style="color:#4df4ff"><strong>}</strong></span>
    <span style="color:#4df4ff"><strong>}</strong></span>

    <span style="color:#f6dd62"><strong>return</strong></span> inSampleSize<span style="color:#4df4ff"><strong>;</strong></span>
<span style="color:#4df4ff"><strong>}</strong></span></code></span></span>

此方法可用于将图像分配给视图,如以下示例所示。

<span style="color:rgba(0, 0, 0, 0.8)"><span style="color:#faf6e4"><code>viewWidth <span style="color:#4df4ff"><strong>=</strong></span> imageView<span style="color:#4df4ff"><strong>.</strong></span><span style="color:#a8e1fe">getWidth</span><span style="color:#4df4ff"><strong>();</strong></span>
viewHeight <span style="color:#4df4ff"><strong>=</strong></span> imageView<span style="color:#4df4ff"><strong>.</strong></span><span style="color:#a8e1fe">getHeight</span><span style="color:#4df4ff"><strong>();</strong></span>

imageView<span style="color:#4df4ff"><strong>.</strong></span>
imageView<span style="color:#4df4ff"><strong>.</strong></span><span style="color:#a8e1fe">setImageBitmap</span><span style="color:#4df4ff"><strong>(</strong></span>
    decodeSampledBitmapFromResource<span style="color:#4df4ff"><strong>(</strong></span>getResources<span style="color:#4df4ff"><strong>(),</strong></span> R<span style="color:#4df4ff"><strong>.</strong></span><span style="color:#a8e1fe">id</span><span style="color:#4df4ff"><strong>.</strong></span><span style="color:#a8e1fe">myimage</span><span style="color:#4df4ff"><strong>,</strong></span> viewWidth<span style="color:#4df4ff"><strong>,</strong></span> viewHeight<span style="color:#4df4ff"><strong>));</strong></span></code></span></span>

3.使用缓存

3.1。使用缓存

缓存允许重用创建昂贵的对象。如果将对象加载到内存中,则可以将其视为对象的缓存。例如,如果从Internet下载图像以在列表中显示它们,则应将它们保存在内存中以避免多次下载它们。

在某些时候,您需要回收一些对象,否则会耗尽内存。这样做的一个好方法是回收在应用程序中使用时间最长的对象。

Android平台提供了 LruCache 类,从API 12开始(或在support-v4库中)。本 LruCache 类提供了一个_least最近使用的缓存_(LRU高速缓存)的缓存实现。LRU缓存会跟踪其成员的使用情况。它具有给定的大小,如果超过此大小,则会删除最长时间未访问的项目。此行为如下图所示。

LRU缓存一般

以下示例代码演示了LruCache用于缓存图像的类的可能实现。

<span style="color:rgba(0, 0, 0, 0.8)"><span style="color:#faf6e4"><code><span style="color:#f6dd62"><strong>public</strong></span> <span style="color:#f6dd62"><strong>class</strong></span> <span style="color:#b2fd6d"><strong>ImageCache</strong></span> <span style="color:#f6dd62"><strong>extends</strong></span> LruCache<span style="color:#4df4ff"><strong><</strong></span>String<span style="color:#4df4ff"><strong>,</strong></span> Bitmap<span style="color:#4df4ff"><strong>></strong></span> <span style="color:#4df4ff"><strong>{</strong></span>
 
  <span style="color:#f6dd62"><strong>public</strong></span> <span style="color:#a8e1fe">ImageCache</span><span style="color:#4df4ff"><strong>(</strong></span> <span style="color:#b2fd6d"><strong>int</strong></span> maxSize <span style="color:#4df4ff"><strong>)</strong></span> <span style="color:#4df4ff"><strong>{</strong></span>
    <span style="color:#f6dd62"><strong>super</strong></span><span style="color:#4df4ff"><strong>(</strong></span> maxSize <span style="color:#4df4ff"><strong>);</strong></span>
  <span style="color:#4df4ff"><strong>}</strong></span>
 
  <span style="color:#b2fd6d"><strong>@Override</strong></span>
  <span style="color:#f6dd62"><strong>protected</strong></span> <span style="color:#b2fd6d"><strong>int</strong></span> <span style="color:#a8e1fe">sizeOf</span><span style="color:#4df4ff"><strong>(</strong></span> String key<span style="color:#4df4ff"><strong>,</strong></span> Bitmap value <span style="color:#4df4ff"><strong>)</strong></span> <span style="color:#4df4ff"><strong>{</strong></span>
    <span style="color:#f6dd62"><strong>return</strong></span> value<span style="color:#4df4ff"><strong>.</strong></span><span style="color:#a8e1fe">getByteCount</span><span style="color:#4df4ff"><strong>();</strong></span>
  <span style="color:#4df4ff"><strong>}</strong></span>
 
  <span style="color:#b2fd6d"><strong>@Override</strong></span>
  <span style="color:#f6dd62"><strong>protected</strong></span> <span style="color:#b2fd6d"><strong>void</strong></span> <span style="color:#a8e1fe">entryRemoved</span><span style="color:#4df4ff"><strong>(</strong></span> <span style="color:#b2fd6d"><strong>boolean</strong></span> evicted<span style="color:#4df4ff"><strong>,</strong></span> String key<span style="color:#4df4ff"><strong>,</strong></span> Bitmap oldValue<span style="color:#4df4ff"><strong>,</strong></span> Bitmap newValue <span style="color:#4df4ff"><strong>)</strong></span> <span style="color:#4df4ff"><strong>{</strong></span>
    oldValue<span style="color:#4df4ff"><strong>.</strong></span><span style="color:#a8e1fe">recycle</span><span style="color:#4df4ff"><strong>();</strong></span>
  <span style="color:#4df4ff"><strong>}</strong></span>
 
<span style="color:#4df4ff"><strong>}</strong></span></code></span></span>

它的用法很简单,并通过以下示例代码进行说明。

<span style="color:rgba(0, 0, 0, 0.8)"><span style="color:#faf6e4"><code>LruCache<span style="color:#4df4ff"><strong><</strong></span>String<span style="color:#4df4ff"><strong>,</strong></span> Bitmap<span style="color:#4df4ff"><strong>></strong></span> bitmapCache <span style="color:#4df4ff"><strong>=</strong></span> <span style="color:#f6dd62"><strong>new</strong></span> LruCache<span style="color:#4df4ff"><strong><</strong></span>String<span style="color:#4df4ff"><strong>,</strong></span> Bitmap<span style="color:#4df4ff"><strong>>();</strong></span></code></span></span>

为了确定高速缓存的初始大小,最好根据设备上可用的总内存来确定大小。为了确定可用的内存你可以MemoryClass。以下代码对此进行了演示。

<span style="color:rgba(0, 0, 0, 0.8)"><span style="color:#faf6e4"><code><span style="color:#b2fd6d"><strong>int</strong></span> memClass <span style="color:#4df4ff"><strong>=</strong></span> <span style="color:#4df4ff"><strong>(</strong></span> <span style="color:#4df4ff"><strong>(</strong></span> ActivityManager<span style="color:#4df4ff"><strong>)</strong></span> activity<span style="color:#4df4ff"><strong>.</strong></span><span style="color:#a8e1fe">getSystemService</span><span style="color:#4df4ff"><strong>(</strong></span> Context<span style="color:#4df4ff"><strong>.</strong></span><span style="color:#a8e1fe">ACTIVITY_SERVICE</span> <span style="color:#4df4ff"><strong>)</strong></span> <span style="color:#4df4ff"><strong>).</strong></span><span style="color:#a8e1fe">getMemoryClass</span><span style="color:#4df4ff"><strong>();</strong></span>
<span style="color:#b2fd6d"><strong>int</strong></span> cacheSize <span style="color:#4df4ff"><strong>=</strong></span> <span style="color:#f696db"><strong>1024</strong></span> <span style="color:#4df4ff"><strong>*</strong></span> <span style="color:#f696db"><strong>1024</strong></span> <span style="color:#4df4ff"><strong>*</strong></span> memClass <span style="color:#4df4ff"><strong>/</strong></span> <span style="color:#f696db"><strong>8</strong></span><span style="color:#4df4ff"><strong>;</strong></span>
LruCache cache <span style="color:#4df4ff"><strong>=</strong></span> <span style="color:#f6dd62"><strong>new</strong></span> LruCache<span style="color:#4df4ff"><strong><</strong></span>String<span style="color:#4df4ff"><strong>,</strong></span> Bitmap<span style="color:#4df4ff"><strong>>(</strong></span> cacheSize <span style="color:#4df4ff"><strong>);</strong></span></code></span></span>

3.2。清理缓存

从API 14开始,您可以覆盖onTrimMemory()Android组件中的方法。Android系统调用此方法,要求您在Android系统需要前台进程资源的情况下清理内存。

 

转自:https://www.vogella.com/tutorials/AndroidApplicationOptimization/article.html

猜你喜欢

转载自blog.csdn.net/mcs712/article/details/95313230