最近在项目遇到的动画效果不好实现,就让UI切成图,采用帧动画实现效果,但是在使用animation-list时,图片也就11张,每张图片大概560k左右,结果内存溢出,崩溃 了,自己用了三张都崩溃;拿代码说;
1.anin_searh.xml
<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:andro
android:oneshot="true">
<item android:drawable="@drawable/a1" android:duration="100"></item>
<item android:drawable="@drawable/a2" android:duration="100"></item>
<item android:drawable="@drawable/a4" android:duration="100"></item>
<item android:drawable="@drawable/a5" android:duration="100"></item>
<item android:drawable="@drawable/a6" android:duration="100"></item>
<item android:drawable="@drawable/a7" android:duration="100"></item>
<item android:drawable="@drawable/a8" android:duration="100"></item>
<item android:drawable="@drawable/a9" android:duration="100"></item>
<item android:drawable="@drawable/a10" android:duration="100"></item>
<item android:drawable="@drawable/a11" android:duration="100"></item>
</animation-list>
2.使用帧动画
search_scale_iv.setBackgroundResource(.anim_search);
AnimationDrawable drawable = (AnimationDrawable) search_scale_iv.getBackground();
();
结果setBackgroundResource出现内存溢出,这个方法其实获取drawable时候,会消耗很多内存,很容易内存溢出,崩溃。
3.解决方法:在网上找了个类,处理,结果我使用11张560k大小图片,没有内存溢出;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import .;
import .;
import ;
import ;
import ;
/****
* 此工具类源于stack over flow
* 原文链接:/questions/8692328/causing-outofmemoryerror-in-frame-by-frame-animation-in-android
* 主要使用了方法通过底层C来绘制图片,有效防止OOM
* 使用了第三方类库:,将Inputstream转为byte字节数组
* *******/
public class MyAnimationDrawable {
public static class MyFrame {
byte[] bytes;
int duration;
Drawable drawable;
boolean isReady = false;
}
public interface OnDrawableLoadedListener {
public void onDrawableLoaded(List<MyFrame> myFrames);
}
// 1
/***
* 性能更优
* 在animation-list中设置时间
* **/
public static void animateRawManuallyFromXML(int resourceId,
final ImageView imageView, final Runnable onStart,
final Runnable onComplete) {
loadRaw(resourceId, (),
new OnDrawableLoadedListener() {
@Override
public void onDrawableLoaded(List<MyFrame> myFrames) {
if (onStart != null) {
();
}
animateRawManually(myFrames, imageView, onComplete);
}
});
}
// 2
private static void loadRaw(final int resourceId, final Context context,
final OnDrawableLoadedListener onDrawableLoadedListener) {
loadFromXml(resourceId, context, onDrawableLoadedListener);
}
// 3
private static void loadFromXml(final int resourceId,
final Context context,
final OnDrawableLoadedListener onDrawableLoadedListener) {
new Thread(new Runnable() {
@Override
public void run() {
final ArrayList<MyFrame> myFrames = new ArrayList<MyFrame>();
XmlResourceParser parser = ().getXml(
resourceId);
try {
int eventType = ();
while (eventType != XmlPullParser.END_DOCUMENT) {
if (eventType == XmlPullParser.START_DOCUMENT) {
} else if (eventType == XmlPullParser.START_TAG) {
if (().equals("item")) {
byte[] bytes = null;
int duration = 1000;
for (int i = 0; i < (); i++) {
if ((i).equals(
"drawable")) {
int resId = (parser
.getAttributeValue(i)
.substring(1));
bytes = (context
.getResources()
.openRawResource(resId));
} else if ((i)
.equals("duration")) {
duration = (
i, 1000);
}
}
MyFrame myFrame = new MyFrame();
= bytes;
= duration;
(myFrame);
}
} else if (eventType == XmlPullParser.END_TAG) {
} else if (eventType == ) {
}
eventType = ();
}
} catch (IOException e) {
();
} catch (XmlPullParserException e2) {
// TODO: handle exception
();
}
// Run on UI Thread
new Handler(()).post(new Runnable() {
@Override
public void run() {
if (onDrawableLoadedListener != null) {
(myFrames);
}
}
});
}
}).run();
}
// 4
private static void animateRawManually(List<MyFrame> myFrames,
ImageView imageView, Runnable onComplete) {
animateRawManually(myFrames, imageView, onComplete, 0);
}
// 5
private static void animateRawManually(final List<MyFrame> myFrames,
final ImageView imageView, final Runnable onComplete,
final int frameNumber) {
final MyFrame thisFrame = (frameNumber);
if (frameNumber == 0) {
= new BitmapDrawable(()
.getResources(), (
, 0, ));
} else {
MyFrame previousFrame = (frameNumber - 1);
((BitmapDrawable) ).getBitmap().recycle();
= null;
= false;
}
();
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
// Make sure ImageView hasn't been changed to a different Image
// in this time
if (() == ) {
if (frameNumber + 1 < ()) {
MyFrame nextFrame = (frameNumber + 1);
if () {
// Animate next frame
animateRawManually(myFrames, imageView, onComplete,
frameNumber + 1);
} else {
= true;
}
} else {
if (onComplete != null) {
();
}
}
}
}
}, );
// Load next frame
if (frameNumber + 1 < ()) {
new Thread(new Runnable() {
@Override
public void run() {
MyFrame nextFrame = (frameNumber + 1);
= new BitmapDrawable(imageView
.getContext().getResources(),
(, 0,
));
if () {
// Animate next frame
animateRawManually(myFrames, imageView, onComplete,
frameNumber + 1);
} else {
= true;
}
}
}).run();
}
}
//第二种方法
/***
* 代码中控制时间,但不精确
* duration = 1000;
* ****/
public static void animateManuallyFromRawResource(
int animationDrawableResourceId, ImageView imageView,
Runnable onStart, Runnable onComplete, int duration) throws IOException,
XmlPullParserException {
AnimationDrawable animationDrawable = new AnimationDrawable();
XmlResourceParser parser = ().getResources()
.getXml(animationDrawableResourceId);
int eventType = ();
while (eventType != XmlPullParser.END_DOCUMENT) {
if (eventType == XmlPullParser.START_DOCUMENT) {
} else if (eventType == XmlPullParser.START_TAG) {
if (().equals("item")) {
Drawable drawable = null;
for (int i = 0; i < (); i++) {
if ((i).equals("drawable")) {
int resId = (parser
.getAttributeValue(i).substring(1));
byte[] bytes = (imageView
.getContext().getResources()
.openRawResource(resId));//
drawable = new BitmapDrawable(imageView
.getContext().getResources(),
(bytes, 0,
));
} else if ((i)
.equals("duration")) {
duration = (i, 66);
}
}
(drawable, duration);
}
} else if (eventType == XmlPullParser.END_TAG) {
} else if (eventType == ) {
}
eventType = ();
}
if (onStart != null) {
();
}
animateDrawableManually(animationDrawable, imageView, onComplete, 0);
}
private static void animateDrawableManually(
final AnimationDrawable animationDrawable,
final ImageView imageView, final Runnable onComplete,
final int frameNumber) {
final Drawable frame = (frameNumber);
(frame);
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
// Make sure ImageView hasn't been changed to a different Image
// in this time
if (() == frame) {
if (frameNumber + 1 < ()) {
// Animate next frame
animateDrawableManually(animationDrawable, imageView,
onComplete, frameNumber + 1);
} else {
// Animation complete
if (onComplete != null) {
();
}
}
}
}
}, (frameNumber));
}
}
这里需要导入jar,
import ; 相关包很多,我只是拿 了需要的jar,下载地址:/detail/daitu_liang/9614639
4.然后通过上述类,来调用自己的动画xml,
(.anim_search,
search_scale_iv, new Runnable() {
@Override
public void run() {
// TODO onStart
// 动画开始时回调
("","start");
}
}, new Runnable() {
@Override
public void run() {
// TODO onComplete
// 动画结束时回调
("","end");
}
});
这样在使用帧动画时,可以有效的适度防止内存溢出,谁还有什么办法,欢迎交流!