工具类 解决帧动画内存泄漏问题
来源:互联网 发布:苏氏钻头淘宝 编辑:程序博客网 时间:2024/06/03 18:37
package com.hp.robot.util;
import android.app.Activity;
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://stackoverflow.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 int soundsId, final Runnable onStart, final Runnable onComplete) { loadRaw(resourceId, imageView.getContext(), new OnDrawableLoadedListener() { @Override public void onDrawableLoaded(List<MyFrame> myFrames) { if (onStart != null) { onStart.run(); } //Intent intent = new Intent(imageView.getContext(), MediaPlayerService.class); //intent.putExtra("soundId",soundsId); //imageView.getContext().startService(intent); animateRawManually(myFrames, imageView, onComplete); } });}//repeat animpublic static AnimationDrawableController animateRawManuallyFromXMLRepeat(int resourceId, final ImageView imageView, final Runnable onStart, final AnimationDrawableController controller ) { loadRaw(resourceId, imageView.getContext(), new OnDrawableLoadedListener() { @Override public void onDrawableLoaded(List<MyFrame> myFrames) { if (onStart != null) { onStart.run(); } //Intent intent = new Intent(imageView.getContext(), MediaPlayerService.class); //intent.putExtra("soundId",soundsId); //imageView.getContext().startService(intent); animateRawManuallyRepeat(myFrames, imageView,0,controller); } }); return controller;}// 2private static void loadRaw(final int resourceId, final Context context, final OnDrawableLoadedListener onDrawableLoadedListener) { loadFromXml(resourceId, context, onDrawableLoadedListener);}// 3private 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();}// 4private static void animateRawManually(List<MyFrame> myFrames, ImageView imageView, Runnable onComplete) { animateRawManually(myFrames, imageView, onComplete, 0);}// 4private static void animateRawManually(List<MyFrame> myFrames, final int soundsId, ImageView imageView, Runnable onComplete) { animateRawManually(myFrames, soundsId,imageView, onComplete, 0);}// 5private 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(); }}// 5private static AnimationDrawableController animateRawManuallyRepeat(final List<MyFrame> myFrames, final ImageView imageView, final int frameNumber, final AnimationDrawableController controller) { if(controller.mStop){ return controller; } 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 animateRawManuallyRepeat(myFrames, imageView, frameNumber + 1,controller); } else { nextFrame.isReady = true; } } else { } } } }, 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 animateRawManuallyRepeat(myFrames, imageView, frameNumber + 1,controller); } else { nextFrame.isReady = true; } } }).run(); }else { animateRawManuallyRepeat(myFrames, imageView, 0,controller); } return controller;}// 5private static void animateRawManually(final List<MyFrame> myFrames, final int soundsId, 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
// MediaPlayer player = MediaPlayer.create(imageView.getContext(), R.raw.crab);
// player.start();
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 { ((Activity) imageView.getContext()).runOnUiThread(onComplete); }
// imageView.getContext().getApplicationContext().run
//
// runOnUiThread(new Runnable()
// {
// public void run()
// {
// mText.setText(“更新界面-runOnUiThread”) ;
// }
//
// });
// }
// 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));}
}
在活动中调用
第一个参数:动画文件
第二个参数:目标view ImagevView
第三个参数:播放动画时候需要播放的音乐资源ID
第四个参数:动画开始时执行的方法Runnable对象
第四个参数:动画结束时执行的方法Runnable对象
MyAnimationDrawable.animateRawManuallyFromXML(R.drawable.robot_hand_anim, mIvRobot, 0, new Runnable() {
@Override
public void run() {
}
},
new Runnable() {
@Override
public void run() {
System.gc();
}
});
动画文件:
- 工具类 解决帧动画内存泄漏问题
- 解决内存泄漏问题
- Xcode工具解决内存泄漏
- 解决 X264 内存泄漏问题
- 解决 X264 内存泄漏问题
- 内存泄漏问题如何解决
- 解决webview内存泄漏问题
- 内存泄漏问题及解决
- 监测内存泄漏问题的工具
- 使用JRockit作为工具检测并解决JAVA内存泄漏问题的一次实战
- 使用JRockit作为工具检测并解决JAVA内存泄漏问题的一次实战.doc
- 【转】使用JRockit作为工具检测并解决JAVA内存泄漏问题的一次实战
- 最近解决的一个内存泄漏问题
- 解决javascript的内存泄漏问题
- 解决VTK使用中的内存泄漏问题
- JRockit 解决JAVA内存泄漏问题
- 解决Solaris应用程序开发内存泄漏问题
- 捉虫记录:解决内存泄漏问题
- 组织敏捷转型中的 HR
- 搜索姿势浅谈
- ubuntu使用apt命令常见报错以及解决方案
- 最长下降子序列 3-5
- jquery对象的定义和使用
- 工具类 解决帧动画内存泄漏问题
- dede织梦后台验证码不显示怎么办
- mysql--18110定位慢查询
- eclipse安装黑色插件方法
- 机器学习初学者必须知道的十大算法
- dedecms模板中dedeajax2.js导致网页无法打开
- IDEA中快捷为类重写equals和hashCode方法
- Java_List常见方法
- 菜鸟学python(01)—— 汉诺塔递归 理解