1. 程式人生 > >Android幀動畫實現,防OOM,比原生動畫集節約超過十倍的資源

Android幀動畫實現,防OOM,比原生動畫集節約超過十倍的資源

2015年專案接到一個需求,實現一個嚮導動畫,這個動畫一共六十張圖片,當時使用的是全志A33的開發(512的記憶體),通過使用Android的動畫集實現,效果特別卡頓,然後想到這種方式來實現,效果很流暢.然後寫成開一個開源專案供大家參考

對比以下兩種方式實現幀動畫,使用相同的80張280x280的png圖片執行動畫,資源佔用情況對比:

Android動畫集實現: 記憶體佔用56M左右

FrameAnimation實現: 記憶體佔用4M左右

兩者CUP佔用都比較低,可忽略

Sample效果:

一、Android動畫集實現幀動畫
  • 1 在drawable目錄下建立動畫集animalist.xml
<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
    android:oneshot="false">

    <!--通過Android動畫集播放的八十張圖片-->
    <item
        android:drawable="@mipmap/c_1"
        android:duration="50" />
    <item
        android:drawable="@mipmap/c_2"
        android:duration="50" />
     <!--  省略...  -->
    <item
        android:drawable="@mipmap/circle_19"
        android:duration="50" />
    <item
        android:drawable="@mipmap/circle_20"
        android:duration="50" />

</animation-list>
  • 2 在佈局檔案ImageView中使用該drawable
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.ansen.frameanimation.sample.MainActivity">

    <ImageView
        android:id="@+id/image"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@drawable/animlist" />

</LinearLayout>

  • 3 在程式碼中呼叫,啟動動畫
    ImageView image = (ImageView) findViewById(R.id.image);

    AnimationDrawable animationDrawable = (AnimationDrawable) image.getDrawable();
        animationDrawable.start();

動畫啟動系統資源佔用情況如下:


手動觸發GC,記憶體佔用幾乎沒改變

二、FrameAnimation實現幀動畫
  • 1 定義需要播放動畫的資原始檔;在arrays檔案中定義資源,或者在程式碼中定義
<?xml version="1.0" encoding="utf-8"?>
<resources>

    <!--通過FrameAnimation播放的八十張圖片-->
    <array name="c">

        <item>@mipmap/c_1</item>
        <item>@mipmap/c_2</item>
        <!-- 省略...  -->
        <item>@mipmap/circle_19</item>
        <item>@mipmap/circle_20</item>
    </array>

</resources>

獲取定義之後的資源陣列(程式碼中可直接定義資原始檔的陣列,便可忽略上一步):

    private int[] getRes() {
        TypedArray typedArray = getResources().obtainTypedArray(R.array.c);
        int len = typedArray.length();
        int[] resId = new int[len];
        for (int i = 0; i < len; i++) {
            resId[i] = typedArray.getResourceId(i, -1);
        }
        typedArray.recycle();
        return resId;
    }
  • 2 在程式碼中呼叫,啟動動畫
    ImageView image = (ImageView) findViewById(R.id.image);

    FrameAnimation frameAnimation = new FrameAnimation(image, getRes(), 50, true);
    frameAnimation.setAnimationListener(new FrameAnimation.AnimationListener() {
        @Override
        public void onAnimationStart() {
            Log.d(TAG, "start");
        }

        @Override
        public void onAnimationEnd() {
            Log.d(TAG, "end");
        }

        @Override
        public void onAnimationRepeat() {
            Log.d(TAG, "repeat");
        }
    });

動畫啟動系統資源佔用情況如下:


手動觸發GC,記憶體佔用有明顯變化

部落格地址