记——Android帧动画开发防止OOM

前言:来自菜鸟程序员的第二篇博客,记录一个可以防止OOM的帧动画开发,方便后面需要用到时复制粘贴。

开发背景:项目要求加上动画显示,UI小姐姐直接给我切了两百多张帧动画图片。好吧,之前看过《第一行代码》和《疯狂Android》,知道可以直接用AnimationDrawable来开发逐帧动画,那就直接开干把,于是改好了那200多张图片的名字,写好了xml文件,兴高采烈地运行程序!……纳尼,java.lang.OutOfMemoryError……一脸懵逼啊!问了旁边的一个同事,他告诉我说图片太多了,内存溢出,然后发给我一个class,说你看一下这个吧,用这个不管有多少图片都不会内存溢出。然后我看了一下,三百多行代码,一个注释都没有(最讨厌看那些一个注释都没有的代码了)。不过也没办法了,好好研究一下吧,里里外外研究并测试了半天给相关的地方加上了注释后,发现好多都可以简化一下,并且简化后也没有出错,瞬间只剩下不到一百行代码了,这里就记录一下简化后的代码。

一、帧动画类

其实这里最关键的就是在play()函数中直接调用了ImageView.postDelayed()方法并在该方法中调用play()函数自己(递归)来实现不停的替换图片。

package com.example.view;

import android.widget.ImageView;

/**
 * 帧动画工具类,防止OOM
 */
public class FrameAnimation {

	/** 是否循环播放 */
	private boolean mIsRepeat;
	/** 播放动画的控件 */
	private ImageView mImageView;
	/** 播放的图片数组 */
	private int[] mFrameRess;
	/** 每帧动画的播放间隔 */
	private int mDuration;
	/** 最后一帧图片 */
	private int mLastFrame;
	/** 暂停 */
	private boolean mPause = true;
	/** 当前帧 */
	private int mCurrentFrame = 0;

	/**
	 * @param iv
	 *            播放动画的控件
	 * @param frameRes
	 *            播放的图片数组
	 * @param duration
	 *            每帧动画的播放间隔(毫秒)
	 * @param isRepeat
	 *            是否循环播放
	 */
	public FrameAnimation(ImageView iv, int[] frameRes, int duration,
			boolean isRepeat) {
		this.mImageView = iv;
		this.mFrameRess = frameRes;
		this.mDuration = duration;
		this.mLastFrame = frameRes.length - 1;
		this.mIsRepeat = isRepeat;
	}

	/** 播放动画 */
	private void play(final int i) {
		mImageView.postDelayed(new Runnable() {

			@Override
			public void run() {
				if (mPause) {
					mCurrentFrame = i;
					return;
				}
				mImageView.setImageResource(mFrameRess[i]);
				if (i == mLastFrame) {
					if (mIsRepeat) {
						play(0);
					}
				} else {
					play(i + 1);
				}
			}
		}, mDuration);
	}

	/** 停止播放 */
	public void stopAnimation() {
		this.mPause = true;
	}

	/** 是否暂停 */
	public boolean isPause() {
		return this.mPause;
	}

	/** 播放动画 */
	public void restartAnimation() {
		if (mPause) {
			mPause = false;
			play(mCurrentFrame);
		}
	}

	/** 关闭动画 */
	public void cancle() {
		if (mImageView != null) {
			stopAnimation();
			mImageView.removeCallbacks(null);
		}
	}

}

二、activity_main.xml布局文件

测试所用,简简单单,一个ImageView用来显示动画,一个Button用来控制动画的暂停和播放。

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
     >
     
    <ImageView
        android:id="@+id/anim_view"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:layout_centerVertical="true"/>
    
    <Button 
        android:id="@+id/pause_anim"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="播放/暂停"
        android:layout_below="@id/anim_view"
        android:layout_centerHorizontal="true"
        android:layout_marginTop="50px"
        />
    
</RelativeLayout>

三、array_hand_anim.xml文件

在values里添加图片资源组array_hand_anim.xml,并且把相应的图片放到drawable-hdpi里去。

<?xml version="1.0" encoding="utf-8"?>
<resources>

    <array name="hand_anim_array">
        <item> @drawable/hand02 </item>
        <item> @drawable/hand04 </item>
        <item> @drawable/hand06 </item>
        <item> @drawable/hand08 </item>
        <item> @drawable/hand10 </item>
        <item> @drawable/hand12 </item>
        <item> @drawable/hand14 </item>
        <item> @drawable/hand16 </item>
        <item> @drawable/hand18 </item>
        <item> @drawable/hand20 </item>
        <item> @drawable/hand22 </item>
        <item> @drawable/hand24 </item>
        <item> @drawable/hand26 </item>
        <item> @drawable/hand28 </item>
        <item> @drawable/hand30 </item>
        <item> @drawable/hand32 </item>
        <item> @drawable/hand34 </item>
        <item> @drawable/hand36 </item>
        <item> @drawable/hand38 </item>
        <item> @drawable/hand40 </item>
        <item> @drawable/hand42 </item>
        <item> @drawable/hand44 </item>
        <item> @drawable/hand46 </item>
    </array>

</resources>

四、MainActivity文件

这里调用帧动画类,调用的时候需要把资源图片的ID以数组的形式传给帧动画类,所以通过TypedArray来获取资源图片的ID,然后通过一个按钮控制动画的播放和暂停。

package com.example.testiev;

import com.example.view.FrameAnimation;

import android.app.Activity;
import android.content.res.TypedArray;
import android.os.Bundle;
import android.view.View;
import android.view.Window;
import android.widget.Button;
import android.widget.ImageView;

public class MainActivity extends Activity {

	/** 动效 */
	private FrameAnimation mAnimation;
	/** 动效View */
	private ImageView anim_view;
	/** 暂停/播放动画 */
	private Button pause_anim;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		requestWindowFeature(Window.FEATURE_NO_TITLE);
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);

		anim_view = (ImageView) findViewById(R.id.anim_view);

		mAnimation = new FrameAnimation(anim_view,
				getRes(R.array.hand_anim_array), 80, true);
		mAnimation.restartAnimation();// 开始动画

		pause_anim = (Button) findViewById(R.id.pause_anim);
		pause_anim.setOnClickListener(new View.OnClickListener() {

			@Override
			public void onClick(View v) {
				if (mAnimation.isPause()) {
					mAnimation.restartAnimation();// 开始动画
				} else {
					mAnimation.stopAnimation();// 关闭动效
				}
			}
		});
	}

	/** 获取需要播放的动画资源 */
	private int[] getRes(int id) {
		TypedArray typedArray = getResources().obtainTypedArray(id);
		int len = typedArray.length();
		int[] resId = new int[len];
		for (int i = 0; i < len; i++) {
			resId[i] = typedArray.getResourceId(i, 0);
		}
		typedArray.recycle();
		return resId;
	}

}

到此一个可以防止OOM的帧动画程序就完成了,下次要用到直接打开复制粘贴,舒服!

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值