近来在写项目时,有遇到使用android原生的序列帧动画时,在部分手机(尤其是内存小的)上出现了OOM问题,这种问题是不可避免的。1.我觉首先你要看看是否有适配问题,因为你选择播放的图片要是没有放入对应的适配drawable文件夹,也会出现OOM问题。别说是连播图片了,就连普通的背景切换都有这种风险。2.要是上述没问题,那么就要换思路了。在网上看别人的解决方法,发现了一种好的方法,利用Handle原理来实现图片快速切换效果,这种方法我用到现在还没有一次OOM过,这我也是借鉴别人的。不BB了,上代码。
写的时候最好在外面套一个try( ) { }catch( OutOfMemoryError e){ System.gc(); } 通过catch去捕捉OOM异常,然后通知gc去回收。其实android里面调用gc并不能马上进行回收,但我觉得这样DoubleAdopting (看过片的都知道)。
新建一个类SceneAnimation:
<span style="font-size:18px;">public class SceneAnimation
{
//传入的关联动画的imageView对象(这里不一定是ImageView也可以是其他)
private ImageView mImageView;
//图片数组对象
private int[] mFrameRess;
//每张图片的动画时长(其长度与图片数组对应,用于设置不同时间间隔)
private int[] mDurations;
//每张图片相同的时长
private int mDuration;
//播放至最后一张图片的下标
private int mLastFrameNo;
private long mBreakDelay;
private int mCode;
public SceneAnimation(Activity activity, ImageView pImageView, int[] pFrameRess, int[] pDurations)
{
IntentActivity = activity;
mImageView = pImageView;
mFrameRess = pFrameRess;
mDurations = pDurations;
mLastFrameNo = pFrameRess.length - 1;
mImageView.setBackgroundResource(mFrameRess[0]);
play(1);
}
public SceneAnimation(ImageView pImageView, int[] pFrameRess, int pDuration)
{
mImageView = pImageView;
mFrameRess = pFrameRess;
mDuration = pDuration;
mLastFrameNo = pFrameRess.length - 1;
mImageView.setBackgroundResource(mFrameRess[0]);
playConstant(1);
}
public SceneAnimation(ImageView pImageView, int[] pFrameRess, int pDuration, int code)
{
mImageView = pImageView;
mFrameRess = pFrameRess;
mDuration = pDuration;
mLastFrameNo = pFrameRess.length - 1;
mCode = code;
mImageView.setBackgroundResource(mFrameRess[0]);
playConstantCode(1);
}
public SceneAnimation(ImageView pImageView, int[] pFrameRess, int pDuration, long pBreakDelay)
{
mImageView = pImageView;
mFrameRess = pFrameRess;
mDuration = pDuration;
mLastFrameNo = pFrameRess.length - 1;
mBreakDelay = pBreakDelay;
mImageView.setBackgroundResource(mFrameRess[0]);
playConstant(1);
}
private void play(final int pFrameNo)
{
mImageView.postDelayed(new Runnable()
{
public void run()
{
mImageView.setBackgroundResource(mFrameRess[pFrameNo]);
// 当播放完成后
if (pFrameNo == mLastFrameNo)
{
// play(0);
}
else
{
play(pFrameNo + 1);
}
}
}, mDurations[pFrameNo]);
}
private void playConstant(final int pFrameNo)
{
mImageView.postDelayed(new Runnable()
{
public void run()
{
mImageView.setBackgroundResource(mFrameRess[pFrameNo]);
if (pFrameNo == mLastFrameNo)
{
// 当动画执行完成后设置imageView可点击
mImageView.setClickable(true);
//播放完成后显示第一张图片
mImageView.setBackgroundResource(mFrameRess[0]);
}
else
{
// 在动画执行时imageView不可点击
mImageView.setClickable(false);
playConstant(pFrameNo + 1);
}
}
}, pFrameNo == mLastFrameNo && mBreakDelay > 0 ? mBreakDelay : mDuration);
}
private void playConstantCode(final int pFrameNo)
{
mImageView.postDelayed(new Runnable()
{
public void run()
{
mImageView.setBackgroundResource(mFrameRess[pFrameNo]);
if (pFrameNo == mLastFrameNo)
{
// 当动画执行完成后设置imageView可点击
mImageView.setClickable(true);
mImageView.setBackgroundResource(mFrameRess[0]);
}
else
{
// 在动画执行时imageView不可点击
mImageView.setClickable(false);
playConstantCode(pFrameNo + 1);
}
}
}, pFrameNo == mLastFrameNo && mBreakDelay > 0 ? mBreakDelay : mDuration);
}
};</span>
上述代码是我在网上借鉴别人的,至不过是优化和添加些注释。我觉得这样差不多可以解决图片频繁轮换OOM问题。要是能根据屏幕的宽高动态设置Bitmap对象大小这样更好
<span style="font-size:18px;"> ImageView.setImageBitmap(ImageUtils.decodeSampledBitmapFromResource(getResources(),
ImageViewRes[position],width,height));</span>
还有就是我记得Xutils中也有关于图片加载方法,
BitmapUtils bitmapUtils = new BitmapUtils(this);不过我个人不喜欢Xutils框架,耦合性太高,扩展性不强,毕竟扶着拐杖是走不远的,还是volley好用(个人观点)
// 加载网络图片
bitmapUtils.display(testImageView, "http://bbs.lidroid.com/static/image/common/logo.png");
// 加载本地图片(路径以/开头, 绝对路径)
bitmapUtils.display(testImageView, "/sdcard/test.jpg");
// 加载assets中的图片(路径以assets开头)
bitmapUtils.display(testImageView, "assets/img/wallpaper.jpg");