問題描述
需要播放序列幀,幀數特別多的時候會oom
問題分析
源代碼每一幀都創建一次bitmap,極度消耗內存
bitmap.recycle并不會立刻回收內存,內存還是會很緊張
問題解決
利用inbitmap,每一幀復用同一片內存區域
//設置Bitmap內存復用
mBitmapOptions.inBitmap = mBitmap;//Bitmap復用內存塊,類似對象池,避免不必要的內存
// 初始化bitmap使用該參數bitmap = BitmapFactory.decodeResource(imageView.getResources(), imageRes, mBitmapOptions);
完整代碼如下
/*** 循環讀取幀---循環播放幀*/public class FramesSequenceAnimation {private int[] mFrames; // 幀數組private int mIndex; // 當前幀private boolean mShouldRun; // 開始/停止播放用private boolean mIsRunning; // 動畫是否正在播放,防止重復播放private SoftReference<ImageView> mSoftReferenceImageView; // 軟引用ImageView,以便及時釋放掉private Handler mHandler;private int mDelayMillis;private OnAnimationStoppedListener mOnAnimationStoppedListener; //播放停止監聽private Bitmap mBitmap = null;private BitmapFactory.Options mBitmapOptions;//Bitmap管理類,可有效減少Bitmap的OOM問題public FramesSequenceAnimation(ImageView imageView, int[] frames, int fps) {mHandler = new Handler();mFrames = frames;mIndex = -1;mSoftReferenceImageView = new SoftReference<ImageView>(imageView);mShouldRun = false;mIsRunning = false;mDelayMillis = 1000 / fps;//幀動畫時間間隔,毫秒imageView.setImageResource(mFrames[0]);// 當圖片大小類型相同時進行復用,避免頻繁GCif (Build.VERSION.SDK_INT >= 11) {Bitmap bmp = ((BitmapDrawable) imageView.getDrawable()).getBitmap();int width = bmp.getWidth();int height = bmp.getHeight();Bitmap.Config config = bmp.getConfig();mBitmap = Bitmap.createBitmap(width, height, config);mBitmapOptions = new BitmapFactory.Options();//設置Bitmap內存復用mBitmapOptions.inBitmap = mBitmap;//Bitmap復用內存塊,類似對象池,避免不必要的內存分配和回收mBitmapOptions.inMutable = true;//解碼時返回可變BitmapmBitmapOptions.inSampleSize = 1;//縮放比例}}//循環讀取下一幀private int getNext() {mIndex++;if (mIndex >= mFrames.length) {mIndex = 0;}return mFrames[mIndex];}/*** 播放動畫,同步鎖防止多線程讀幀時,數據安全問題*/public synchronized void start() {mShouldRun = true;if (mIsRunning) {return;}Runnable runnable = new Runnable() {@Overridepublic void run() {ImageView imageView = mSoftReferenceImageView.get();if (!mShouldRun || imageView == null) {mIsRunning = false;if (mOnAnimationStoppedListener != null) {mOnAnimationStoppedListener.AnimationStopped();}return;}mIsRunning = true;//新開線程去讀下一幀mHandler.postDelayed(this, mDelayMillis);if (imageView.isShown()) {int imageRes = getNext();if (mBitmap != null) { // so Build.VERSION.SDK_INT >= 11Bitmap bitmap = null;try {bitmap = BitmapFactory.decodeResource(imageView.getResources(), imageRes, mBitmapOptions);} catch (Exception e) {e.printStackTrace();}if (bitmap != null) {imageView.setImageBitmap(bitmap);} else {imageView.setImageResource(imageRes);mBitmap.recycle();mBitmap = null;}} else {imageView.setImageResource(imageRes);}}}};mHandler.post(runnable);}/*** 停止播放*/public synchronized void stop() {mShouldRun = false;if (mHandler != null) {mHandler.removeCallbacksAndMessages(null);}}/*** 設置停止播放監聽** @param listener*/public void setOnAnimStopListener(OnAnimationStoppedListener listener) {this.mOnAnimationStoppedListener = listener;}}