最近遇到了需要播放大量幀動(dòng)畫(100張以上)的需求芍锦,使用傳統(tǒng)xml幀動(dòng)畫方式掏湾,會(huì)頻繁O(jiān)OM裹虫,為了解決這個(gè)問題,進(jìn)行了幾種嘗試融击,目前的解決方案如下:
傳統(tǒng)幀動(dòng)畫
- 我們需要在drawable目錄下創(chuàng)建動(dòng)畫集animalist.xml
<animation-list xmlns:android="http://schemas.android.com/apk/res/android" android:oneshot="false"> <item android:drawable="@mipmap/image_1" android:duration="50" /> <item android:drawable="@mipmap/image_2" android:duration="50" /> <!-- 省略... --> <item android:drawable="@mipmap/image_99" android:duration="50" /> <item android:drawable="@mipmap/image_100" android:duration="50" /> </animation-list>
經(jīng)過嘗試筑公,圖片不是很大的時(shí)候,大概到20幾張圖片的時(shí)候就會(huì)OOM
解決方案
寫了一個(gè)處理類尊浪,使用方法很簡單下邊直接上代碼
先貼一下調(diào)用代碼,真的很簡單
FrameLoader.into(mImageView).load(mTest).setEndlessLoop(true).setLoopCount(3).play(200);
直接上代碼,懶得看的人可以直接去看Github源碼
Github地址
這是核心處理類
/**
* Created with Android Studio.
*
* @author Kimger
* @email kimger@onetos.cc
* @date 2018-7-13 00:01
*/
public class Process {
/**
* 播方動(dòng)畫的相應(yīng)布局
*/
private ImageView mImageView;
/**
* 播放動(dòng)畫的圖片數(shù)組
*/
private int[] mImageRes;
/**
* 是否需要停止
*/
private boolean stop;
/**
* 記錄播放狀態(tài)
*/
private boolean playing;
/**
* 當(dāng)前播放第*張
*/
private int pImageNo;
/**
* 圖片刷新頻率
*/
private int pImageFrequency;
/**
* 是否無限循環(huán)播放
*/
private boolean endlessLoop = false;
/**
* 循環(huán)次數(shù)匣屡,不定義默認(rèn)為1
*/
private int loopCount = 1;
/**
* 記錄當(dāng)前循環(huán)了幾次
*/
private int countCache;
private String mTag = getClass().getName();
private static Process mInstance;
private static List<ImageView> mObjects ;
private static Map<ImageView, Process> mProcessMap;
private static Pools.SynchronizedPool<Process> sPool = new Pools.SynchronizedPool<>(20);
/**
* 創(chuàng)建新的對象
*
* @return
*/
public static Process build(ImageView tag){
mInstance = obtain();
mInstance.into(tag);
return mInstance;
}
public static Process obtain(){
Process acquire = sPool.acquire();
return (acquire != null) ? acquire : new Process();
}
public void recycle(){
sPool.release(this);
}
/**
* 設(shè)置動(dòng)畫的ImageView
*
* @param pImageView
* @return
*/
private Process into(ImageView pImageView) {
stop = true;
if (mImageView != null) {
mImageView.removeCallbacks(mRunnable);
}
if (pImageView != mImageView) {
stop();
}
this.mImageRes = null;
this.mImageView = pImageView;
return mInstance;
}
/**
* 設(shè)置動(dòng)畫數(shù)組文件
*
* @param pImageRes
* @return
*/
public Process load(int[] pImageRes) {
this.mImageRes = pImageRes;
return mInstance;
}
/**
* 開始播放
*
* @param pImageNo
* @param frequency
*/
public Process play(int pImageNo, int frequency) {
stop = false;
this.pImageNo = pImageNo;
this.pImageFrequency = frequency;
mImageView.postDelayed(mRunnable, frequency);
return mInstance;
}
public Process play(int frequency) {
return play(0, frequency);
}
private Runnable mRunnable = new Runnable() {
@Override
public void run() {
if (stop) {
playing = false;
return;
} else {
mImageView.setImageResource(mImageRes[pImageNo]);
if (pImageNo >= mImageRes.length - 1) {
countCache++;
if (endlessLoop) {
pImageNo = 0;
play(pImageNo, pImageFrequency);
playing = true;
} else {
if (countCache >= loopCount) {
playing = false;
stop();
return;
} else {
pImageNo = 0;
play(pImageNo, pImageFrequency);
playing = true;
}
}
} else {
play(pImageNo + 1, pImageFrequency);
playing = true;
}
}
}
};
public boolean isStop() {
return stop;
}
private void setStop(boolean stop) {
this.stop = stop;
}
/**
* 停止播放
*/
public void stop() {
setStop(true);
countCache = 0;
if (mImageView != null) {
mImageView.removeCallbacks(mRunnable);
System.gc();
recycle();
}
if (mProcessMap != null) {
mProcessMap.clear();
}
if (mObjects != null) {
mObjects.clear();
}
}
public boolean isPlaying() {
return playing;
}
/**
* 是否無限循環(huán)
*/
public Process setEndlessLoop(boolean endlessLoop) {
this.endlessLoop = endlessLoop;
return mInstance;
}
/**
* 循環(huán)次數(shù)
*/
public Process setLoopCount(int loopCount) {
this.loopCount = loopCount;
return mInstance;
}
}
Manager類,留給后續(xù)添加功能的空間
/**
* Created with Android Studio.
*
* @author Kimger
* @email kimger@onetos.cc
* @date 2018-7-13 00:20
*/
public class ProcessManager {
private static ProcessManager mInstance;
public static ProcessManager get(){
if (mInstance == null) {
synchronized (ProcessManager.class){
if (mInstance == null) {
mInstance = new ProcessManager();
}
}
}
return mInstance;
}
}
這是調(diào)用類
/**
* Create with Android Studio.
*
* @author Kimger
* @email kimger@onetos.cc
* @date 2018-7-13 00:30
*/
public class FrameLoader {
public static Process into(ImageView tag){
return Process.build(tag);
}
/**
* 此功能暫時(shí)無法使用
*/
public static Process getProcessByTag(ImageView tag){
Map<ImageView, Process> imageViewProcessMap = ProcessManager.get().getmProcessMap();
if (imageViewProcessMap != null) {
return imageViewProcessMap.get(tag);
}
return null;
}
}
然后就可以愉快的去使用幀動(dòng)畫了拇涤,親測二百張也沒什么問題捣作。