Android 播放帧动画时,发现项目内存太高,就使用一个播放帧动画的工具类,方便以后使用。直接上代码。
工具类代码
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.util.Log;
import android.view.View;
import android.widget.ImageView;
import java.util.HashMap;
/**
* 播放帧动画
*/
public class FrameAnimationManager {
private final static String TAG = "FrameAnimationUtils";
private static volatile FrameAnimationManager mInstance;
private HashMap<Integer, Integer> hashMap = new HashMap();
/**
* 获取单例
*/
public static FrameAnimationManager getInstance() {
if (mInstance == null) {
synchronized (FrameAnimationManager.class) {
if (mInstance == null) {
mInstance = new FrameAnimationManager();
}
}
}
return mInstance;
}
public FramesAnimation createFramesAnimation() {
return new FramesAnimation();
}
/**
* 循环读取帧---循环播放帧
*/
public class FramesAnimation {
/**
* 帧数组
*/
private int[] mFrames;
/**
* 当前帧
*/
private volatile int mIndex;
/**
* 开始/停止播放用
*/
private volatile boolean mShouldRun;
/**
* 动画是否正在播放,防止重复播放
*/
private boolean mIsRunning;
/**
* 软引用ImageView,以便及时释放掉
*/
private ImageView mSoftReferenceImageView;
private Handler mHandler;
private int mDelayMillis;
private int fps;
private boolean isRepeat;
private int lastPictureId = -1;//播放的最后一帧的图片ID
private Bitmap mBitmap;
/**
* Bitmap管理类,可有效减少Bitmap的OOM问题
*/
private BitmapFactory.Options mBitmapOptions;
/**
* 播放监听
*/
private AnimationListener animationListener;
FramesAnimation() {
mHandler = new Handler();
}
/**
* @param imageView image组件
* @param fps FPS为每秒播放帧数,FPS = 1/T,(T--每帧间隔时间秒)
* @param isRepeat 是否重复播放
* @return 帧动画
*/
public void setFrameData(ImageView imageView, int[] frames, int fps, boolean isRepeat) {
mFrames = frames;
this.fps = fps;
mIndex = -1;
mSoftReferenceImageView = imageView;
mShouldRun = false;
mIsRunning = false;
//帧动画时间间隔,毫秒
mDelayMillis = 1000 / fps;
this.isRepeat = isRepeat;
// 当图片大小类型相同时进行复用,避免频繁GC
Bitmap bmp = ((BitmapDrawable) imageView.getDrawable()).getBitmap();
// Bitmap bmp = ((BitmapDrawable) imageView.getBackground()).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内存复用
//Bitmap复用内存块,类似对象池,避免不必要的内存分配和回收
mBitmapOptions.inBitmap = mBitmap;
//解码时返回可变Bitmap
mBitmapOptions.inMutable = true;
//缩放比例
mBitmapOptions.inSampleSize = 1;
}
/**
* 设置帧数
*
* @param fps 帧数
*/
public synchronized void setFps(int fps) {
this.fps = fps;
mDelayMillis = 1000 / fps;
}
/**
* 设置帧数
*
* @param fpsRat 速率
*/
public synchronized void setFpsRat(float fpsRat) {
mDelayMillis = (int) (1000 / (fps * fpsRat));
}
/**
* 循环读取下一帧
*
* @return 下一帧
*/
private int getNext() {
mIndex++;
if (mIndex >= mFrames.length) {
mIndex = 0;
if (!isRepeat) {
mShouldRun = false;
}
}
return mFrames[mIndex];
}
/**
* 播放动画,同步锁防止多线程读帧时,数据安全问题
*/
public synchronized void start() {
mShouldRun = true;
if (mIsRunning) {
return;
}
if (animationListener != null) {
animationListener.onAnimationStarted();
}
Runnable runnable = new Runnable() {
@Override
public void run() {
int imageRes = getNext();
ImageView imageView = mSoftReferenceImageView;
if (!mShouldRun || imageView == null) {
mIsRunning = false;
if (animationListener != null) {
animationListener.onAnimationStopped();
}
return;
}
mIsRunning = true;
//新开线程去读下一帧
mHandler.postDelayed(this, mDelayMillis);
setFrameImage(imageView, imageRes);
}
};
mHandler.post(runnable);
}
/**
* 停止播放
*/
public synchronized void stop() {
if (!mShouldRun) {
return;
}
mShouldRun = false;
mIndex = 0;
}
private void setFrameImage(ImageView imageView, int imageRes) {
lastPictureId = imageRes;
if (!imageView.isShown()) {
imageView.setVisibility(View.VISIBLE);
}
if (mBitmap != null) {
Bitmap 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);
}
}
public int getLastPictureId() {
return lastPictureId;
}
/**
*
*/
public synchronized boolean isRunning() {
return mShouldRun;
}
/**
* 设置播放监听
*
* @param listener 动画停止的监听
*/
public FramesAnimation setAnimationListener(AnimationListener listener) {
this.animationListener = listener;
return this;
}
}
/**
* 从xml中读取帧数组
*
* @param resId 动画资源arrayIds
*/
private int[] getData(Context context, int resId) {
TypedArray array = context.getResources().obtainTypedArray(resId);
int len = array.length();
int[] intArray = new int[len];
for (int i = 0; i < len; i++) {
intArray[i] = array.getResourceId(i, 0);
}
array.recycle();
return intArray;
}
/**
* 播放监听
*/
public interface AnimationListener {
/**
* 开始播放
*/
void onAnimationStarted();
/**
* 停止播放
*/
void onAnimationStopped();
}
}
使用方式如下:
第一步下xml布局中
<ImageView
android:id="@+id/test_img"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_marginTop="@dimen/dimen228dp"
android:src="@drawable/img_energyflow_car0" />
第二步,在java中添加图片数组播放动画即可
private ImageView animationImg;//播放动画的背景
private FrameAnimationManager.FramesAnimation framesAnimation;
//动画图片ID数组
public static int[] imgArr = {R.drawable.img0, R.drawable.img1, R.drawable.img2};
private void initView(View view) {
animationImg = view.findViewById(R.id.test_img);
framesAnimation = FrameAnimationManager.getInstance().createFramesAnimation();
//播放动画
startAnimation(imgArr,20);
}
//播放动画
private void startAnimation(int[] frames, int delay) {
if (framesAnimation.isRunning()) {
LogUtils.d(TAG, "startAnimation animation is running");
framesAnimation.stop();
}
framesAnimation.setFrameData(animationImg, frames, delay, true);
framesAnimation.start();
LogUtils.d(TAG, "startAnimation start() ");
}
以上就是工具类和使用方法,分享出来希望可以有人用到。