1. 程式人生 > >解決animation-list載入多張幀動畫導致OOM的問題---surfaceview用法

解決animation-list載入多張幀動畫導致OOM的問題---surfaceview用法

這次介面改版中有幾個介面的動畫實在酷炫,只有讓UI出一組png用幀動畫的形式展示了。心想著,這不簡單:

<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
    android:oneshot="false">
    <item
        android:drawable="@mipmap/volume_00000"
        android:duration="100" />
    <item
        android:drawable="@mipmap/volume_00001"
        android:duration="100" />
    <item
        android:drawable="@mipmap/volume_00002"
        android:duration="100" />
    <item
        android:drawable="@mipmap/volume_00003"
        android:duration="100" />
</animation-list>

完事~~

但是:微笑微笑微笑


尼瑪啊發火~~~~~~~~~將近6000張圖片尷尬,我用腳趾頭想都知道用animation-list肯定直接要爆炸了微笑微笑微笑

怎麼辦,麼辦,辦?當時心情是崩潰的微笑微笑微笑

-----------------------------------------------------------------分割線-------------------------------------------------------------

聰明的大腦稍微這麼一轉 surfaceView

程式碼註釋很詳細不廢話直接貼~~

package com.meizu.speaker.view;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.PixelFormat;
import android.graphics.PorterDuff;
import android.util.AttributeSet;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;

import com.meizu.speaker.R;

/**
 * Created by zhangxiaotong on 2016/11/1.
 */
public class recycleSurfaceView extends SurfaceView implements SurfaceHolder.Callback,Runnable{

    private String TAG = this.getClass().getSimpleName();
    private final SurfaceHolder mHolder;
    private Thread mThread;
    private long mFrameSpaceTime = 80;  // 每幀圖片的間隔時間
    private boolean mIsDraw = true;     // 畫圖開關
    private int mCurrentIndext = 0;     // 當前正在播放的png

    public int mBitmapResourceIds[] = {
            R.mipmap.menu_00002, R.mipmap.menu_00004, R.mipmap.menu_00006, R.mipmap.menu_00008, R.mipmap.menu_00010, R.mipmap.menu_00012,
            R.mipmap.menu_00014, R.mipmap.menu_00016, R.mipmap.menu_00018, R.mipmap.menu_00020, R.mipmap.menu_00022, R.mipmap.menu_00024,
            R.mipmap.menu_00026, R.mipmap.menu_00028, R.mipmap.menu_00030, R.mipmap.menu_00032, R.mipmap.menu_00034, R.mipmap.menu_00036,
            R.mipmap.menu_00038, R.mipmap.menu_00040, R.mipmap.menu_00042, R.mipmap.menu_00044, R.mipmap.menu_00046, R.mipmap.menu_00048,
            R.mipmap.menu_00050, R.mipmap.menu_00052, R.mipmap.menu_00054, R.mipmap.menu_00056, R.mipmap.menu_00058, R.mipmap.menu_00060,
            R.mipmap.menu_00062, R.mipmap.menu_00064, R.mipmap.menu_00066, R.mipmap.menu_00068, R.mipmap.menu_00070, R.mipmap.menu_00072,
            R.mipmap.menu_00074, R.mipmap.menu_00076, R.mipmap.menu_00078, R.mipmap.menu_00080, R.mipmap.menu_00082, R.mipmap.menu_00084,
            R.mipmap.menu_00086, R.mipmap.menu_00088, R.mipmap.menu_00090, R.mipmap.menu_00092, R.mipmap.menu_00094, R.mipmap.menu_00096,
            R.mipmap.menu_00098, R.mipmap.menu_00100, R.mipmap.menu_00102, R.mipmap.menu_00104, R.mipmap.menu_00106, R.mipmap.menu_00108,
            R.mipmap.menu_00110, R.mipmap.menu_00112, R.mipmap.menu_00114, R.mipmap.menu_00116, R.mipmap.menu_00118, R.mipmap.menu_00120,
            R.mipmap.menu_00122, R.mipmap.menu_00124, R.mipmap.menu_00126, R.mipmap.menu_00128, R.mipmap.menu_00130, R.mipmap.menu_00132,
            R.mipmap.menu_00134, R.mipmap.menu_00136, R.mipmap.menu_00138, R.mipmap.menu_00140, R.mipmap.menu_00142, R.mipmap.menu_00144,
            R.mipmap.menu_00146, R.mipmap.menu_00148, R.mipmap.menu_00150, R.mipmap.menu_00152, R.mipmap.menu_00154, R.mipmap.menu_00156,
            R.mipmap.menu_00158, R.mipmap.menu_00160, R.mipmap.menu_00162, R.mipmap.menu_00164, R.mipmap.menu_00166, R.mipmap.menu_00168,
            R.mipmap.menu_00170, R.mipmap.menu_00172, R.mipmap.menu_00174, R.mipmap.menu_00176, R.mipmap.menu_00178, R.mipmap.menu_00180,
            R.mipmap.menu_00182, R.mipmap.menu_00184, R.mipmap.menu_00186, R.mipmap.menu_00188, R.mipmap.menu_00190, R.mipmap.menu_00000
    };
    private Bitmap mBitmap;

    public recycleSurfaceView(Context context) {this(context,null);}

    public recycleSurfaceView(Context context, AttributeSet attrs) {this(context,attrs,0);}

    public recycleSurfaceView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        mHolder = this.getHolder();       // 獲得surfaceholder
        mHolder.addCallback(this);        // 添加回調,這樣三個方法才會執行

        setZOrderOnTop(true);
        mHolder.setFormat(PixelFormat.TRANSLUCENT);// 設定背景透明
    }

    /**
    首先繼承SurfaceView,並實現SurfaceHolder.Callback介面,實現它的三個方法:
    surfaceCreated(SurfaceHolder holder):surface建立的時候呼叫,一般在該方法中啟動繪圖的執行緒。
    surfaceChanged(SurfaceHolder holder, int format, int width,int height):surface尺寸發生改變的時候呼叫,如橫豎屏切換。
    surfaceDestroyed(SurfaceHolder holder) :surface被銷燬的時候呼叫,如退出遊戲畫面,一般在該方法中停止繪圖執行緒。
    還需要獲得SurfaceHolder,並添加回調函式,這樣這三個方法才會執行。
    */

    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        Log.d(TAG, "surfaceCreated: ");
        if(mBitmapResourceIds == null){
            Log.e(TAG, "surfaceCreated: 圖片資源為空");
            return;
        }
        mThread = new Thread(this);
        mThread.start();
        mIsDraw = true;
    }

    public void setmBitmapResourceIds(int[] mBitmapResourceIds) {
        this.mBitmapResourceIds = mBitmapResourceIds;
    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {

    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        mIsDraw = false;
        try {
            Thread.sleep(mFrameSpaceTime);
            Log.d(TAG, "surfaceDestroyed: Thread " + mThread.getState());
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void run() {
        synchronized (mHolder) {         // 這裡加鎖為了以後控制這個繪製執行緒的wait與notify
            while (mIsDraw) {
                try {
                    drawView();
                    Thread.sleep(mFrameSpaceTime);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    private void drawView() {
        Log.i(TAG, "drawView: ");
        Canvas mCanvas = mHolder.lockCanvas();      // 鎖定畫布
        try {
            mCanvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);        // 清除螢幕
            mCanvas.drawColor(Color.BLACK);

            mBitmap = BitmapFactory.decodeResource(getResources(), mBitmapResourceIds[mCurrentIndext]);
            mCanvas.drawBitmap(mBitmap, 0, 0, null);

            if (mCurrentIndext == mBitmapResourceIds.length - 1) {
                mCurrentIndext = 0;
            }
        }
        catch (Exception e) {
            e.printStackTrace();
        }
        finally {
            mCurrentIndext++;
            if (mCanvas != null) {
                mHolder.unlockCanvasAndPost(mCanvas);       // 提交畫布
            }
            recycle(mBitmap);  // 這裡回收資源非常重要!
        }
    }

    private void recycle(Bitmap mBitmap) {
        if(mBitmap != null)
            mBitmap.recycle();
    }
}


佈局檔案:
    <com.meizu.speaker.view.recycleSurfaceView
     android:id="@+id/anim"
     android:layout_width="@dimen/common_margin_31"
     android:layout_height="@dimen/common_margin_240"
     android:layout_centerVertical="true"
     android:layout_marginStart="@dimen/common_margin_60"
     android:scaleType="fitXY"/> 


預覽~~