Android 使用帧动画内存溢出解决方案
程序员文章站
2024-02-23 11:04:22
android 使用帧动画内存溢出解决方案
最近在项目遇到的动画效果不好实现,就让ui切成图,采用帧动画实现效果,但是在使用animation-list时,图片也就11张...
android 使用帧动画内存溢出解决方案
最近在项目遇到的动画效果不好实现,就让ui切成图,采用帧动画实现效果,但是在使用animation-list时,图片也就11张,每张图片大概560k左右,结果内存溢出,崩溃 了,自己用了三张都崩溃;拿代码说;
1.anin_searh.xml
<?xml version="1.0" encoding="utf-8"?> <animation-list xmlns:android="http://schemas.android.com/apk/res/android" 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(r.drawable.anim_search); animationdrawable drawable = (animationdrawable) search_scale_iv.getbackground(); drawable.start();
结果setbackgroundresource出现内存溢出,这个方法其实获取drawable时候,会消耗很多内存,很容易内存溢出,崩溃。
3.解决方法:在网上找了个类,处理,结果我使用11张560k大小图片,没有内存溢出;
import android.content.context; import android.content.res.xmlresourceparser; import android.graphics.bitmapfactory; import android.graphics.drawable.animationdrawable; import android.graphics.drawable.bitmapdrawable; import android.graphics.drawable.drawable; import android.os.handler; import android.widget.imageview; import org.apache.commons.io.ioutils; import org.xmlpull.v1.xmlpullparser; import org.xmlpull.v1.xmlpullparserexception; import java.io.ioexception; import java.util.arraylist; import java.util.list; /**** * 此工具类源于stack over flow * 原文链接:http://*.com/questions/8692328/causing-outofmemoryerror-in-frame-by-frame-animation-in-android * 主要使用了bitmapfactory.decodebytearray方法通过底层c来绘制图片,有效防止oom * 使用了第三方类库:org.apache.commons.io.ioutils,将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, imageview.getcontext(), new ondrawableloadedlistener() { @override public void ondrawableloaded(list<myframe> myframes) { if (onstart != null) { onstart.run(); } 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 = context.getresources().getxml( resourceid); try { int eventtype = parser.geteventtype(); while (eventtype != xmlpullparser.end_document) { if (eventtype == xmlpullparser.start_document) { } else if (eventtype == xmlpullparser.start_tag) { if (parser.getname().equals("item")) { byte[] bytes = null; int duration = 1000; for (int i = 0; i < parser.getattributecount(); i++) { if (parser.getattributename(i).equals( "drawable")) { int resid = integer.parseint(parser .getattributevalue(i) .substring(1)); bytes = ioutils.tobytearray(context .getresources() .openrawresource(resid)); } else if (parser.getattributename(i) .equals("duration")) { duration = parser.getattributeintvalue( i, 1000); } } myframe myframe = new myframe(); myframe.bytes = bytes; myframe.duration = duration; myframes.add(myframe); } } else if (eventtype == xmlpullparser.end_tag) { } else if (eventtype == xmlpullparser.text) { } eventtype = parser.next(); } } catch (ioexception e) { e.printstacktrace(); } catch (xmlpullparserexception e2) { // todo: handle exception e2.printstacktrace(); } // run on ui thread new handler(context.getmainlooper()).post(new runnable() { @override public void run() { if (ondrawableloadedlistener != null) { ondrawableloadedlistener.ondrawableloaded(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 = myframes.get(framenumber); if (framenumber == 0) { thisframe.drawable = new bitmapdrawable(imageview.getcontext() .getresources(), bitmapfactory.decodebytearray( thisframe.bytes, 0, thisframe.bytes.length)); } else { myframe previousframe = myframes.get(framenumber - 1); ((bitmapdrawable) previousframe.drawable).getbitmap().recycle(); previousframe.drawable = null; previousframe.isready = false; } imageview.setimagedrawable(thisframe.drawable); new handler().postdelayed(new runnable() { @override public void run() { // make sure imageview hasn't been changed to a different image // in this time if (imageview.getdrawable() == thisframe.drawable) { if (framenumber + 1 < myframes.size()) { myframe nextframe = myframes.get(framenumber + 1); if (nextframe.isready) { // animate next frame animaterawmanually(myframes, imageview, oncomplete, framenumber + 1); } else { nextframe.isready = true; } } else { if (oncomplete != null) { oncomplete.run(); } } } } }, thisframe.duration); // load next frame if (framenumber + 1 < myframes.size()) { new thread(new runnable() { @override public void run() { myframe nextframe = myframes.get(framenumber + 1); nextframe.drawable = new bitmapdrawable(imageview .getcontext().getresources(), bitmapfactory.decodebytearray(nextframe.bytes, 0, nextframe.bytes.length)); if (nextframe.isready) { // animate next frame animaterawmanually(myframes, imageview, oncomplete, framenumber + 1); } else { nextframe.isready = 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 = imageview.getcontext().getresources() .getxml(animationdrawableresourceid); int eventtype = parser.geteventtype(); while (eventtype != xmlpullparser.end_document) { if (eventtype == xmlpullparser.start_document) { } else if (eventtype == xmlpullparser.start_tag) { if (parser.getname().equals("item")) { drawable drawable = null; for (int i = 0; i < parser.getattributecount(); i++) { if (parser.getattributename(i).equals("drawable")) { int resid = integer.parseint(parser .getattributevalue(i).substring(1)); byte[] bytes = ioutils.tobytearray(imageview .getcontext().getresources() .openrawresource(resid));//ioutils.readbytes drawable = new bitmapdrawable(imageview .getcontext().getresources(), bitmapfactory.decodebytearray(bytes, 0, bytes.length)); } else if (parser.getattributename(i) .equals("duration")) { duration = parser.getattributeintvalue(i, 66); } } animationdrawable.addframe(drawable, duration); } } else if (eventtype == xmlpullparser.end_tag) { } else if (eventtype == xmlpullparser.text) { } eventtype = parser.next(); } if (onstart != null) { onstart.run(); } animatedrawablemanually(animationdrawable, imageview, oncomplete, 0); } private static void animatedrawablemanually( final animationdrawable animationdrawable, final imageview imageview, final runnable oncomplete, final int framenumber) { final drawable frame = animationdrawable.getframe(framenumber); imageview.setimagedrawable(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 (imageview.getdrawable() == frame) { if (framenumber + 1 < animationdrawable.getnumberofframes()) { // animate next frame animatedrawablemanually(animationdrawable, imageview, oncomplete, framenumber + 1); } else { // animation complete if (oncomplete != null) { oncomplete.run(); } } } } }, animationdrawable.getduration(framenumber)); } }
这里需要导入jar,
import org.apache.commons.io.ioutils;
4.然后通过上述类,来调用自己的动画xml,
myanimationdrawable.animaterawmanuallyfromxml(r.drawable.anim_search, search_scale_iv, new runnable() { @override public void run() { // todo onstart // 动画开始时回调 log.d("","start"); } }, new runnable() { @override public void run() { // todo oncomplete // 动画结束时回调 log.d("","end"); } });
这样在使用帧动画时,可以有效的适度防止内存溢出,谁还有什么办法,欢迎交流!
感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!