Android 逐帧动画AnimationDrawable 内存溢出的一个解决方法

 

要实现的效果如下:

这个是什么相信知道安卓版本彩蛋的同学就知道了,刚开始在低分辨率是有用的,但是到了高分辨率就会报 内存溢出 的错

这是res/anim/lollipopshow.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/anim0" android:duration="150" />
    <item android:drawable="@drawable/anim1" android:duration="150" />
    <item android:drawable="@drawable/anim2" android:duration="100" />
    <item android:drawable="@drawable/anim3" android:duration="100" />
    <item android:drawable="@drawable/anim4" android:duration="100" />
    <item android:drawable="@drawable/anim5" android:duration="100" />
    <item android:drawable="@drawable/anim6" android:duration="100" />
    <item android:drawable="@drawable/anim7" android:duration="100" />
    <item android:drawable="@drawable/anim8" android:duration="100" />
    <item android:drawable="@drawable/anim9" android:duration="100" />
</animation-list>

就10张图片,感觉都不大,但就是报错了T_T,后来上网查了查,改了改,就OK了

这是改后的

public class VersionEggSwitch extends Activity {

    private static final String LOG_TAG = "VersionEggSwitch";
    private static boolean DEBUG = true;// false;
    private static final int NEXT_IMG = 0;
    private ImageView mNextImg;
    private ImageView mBgImage;
    private int loopIndex = 0;
    private SwitchHandler mHandler;
    private AnimationDrawable animationDrawable;
    private FrameLayout mlollipop_main = null;
    private WallpaperManager mWm;
    private int[] image_resource;
    private int[] image_duration;
    private int MaxNum = 10;
    private int initCount = 0;
    private boolean canClicked = false;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        // TODO Auto-generated method stub
        super.onCreate(savedInstanceState);

        Log.d(LOG_TAG, "onCreate()");
        // 隐藏标题栏
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        // 隐藏状态栏
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
                WindowManager.LayoutParams.FLAG_FULLSCREEN);

        setContentView(R.layout.lollipop_main);
        mlollipop_main = (FrameLayout) findViewById(R.id.lollipop_main);
        Set_lollipop_main_Background();
        image_resource = new int[MaxNum];
        image_duration = new int[MaxNum];
        mHandler = new SwitchHandler();
        mBgImage = (ImageView) findViewById(R.id.egg_bg);

        // mBgImage.setImageResource(0);
        // mBgImage.setImageResource(R.anim.lollipopshow);
        getFrameAndDuration(this, R.anim.lollipopshow);

        // animationDrawable = (AnimationDrawable) mBgImage.getDrawable();
        // // animationDrawable.start();

        mNextImg = (ImageView) findViewById(R.id.bgswitch);
        mNextImg.setOnClickListener(new ButtonListener());
    }

    @Override
    public void onWindowFocusChanged(boolean hasFocus) {
        if(!hasFocus) return;
        loadBitmap(mBgImage, image_resource, image_duration);
        Log.d(LOG_TAG, "onWindowFocusChanged();hasFocus=" + hasFocus);
        if (animationDrawable != null) {
            animationDrawable.start();
        }
        int duration = 0;
        for (int i = 0; i < animationDrawable.getNumberOfFrames(); i++) {
            duration += animationDrawable.getDuration(i);
        }
        Handler handler = new Handler();
        handler.postDelayed(new Runnable() {
            public void run() {
                // 此处调用第二个动画播放方法
                if (animationDrawable != null) {
                    animationDrawable.stop();
                    animationDrawable = null; // 这句话为解决内存溢出的关键,开始没有添加
                }

                // mlollipop_main.removeView(mBgImage);
                canClicked = true;
                mBgImage.setImageResource(0);
                mBgImage.setImageResource(R.drawable.loop0);
                System.gc();
            }
        }, duration);

        super.onWindowFocusChanged(hasFocus);

    }

    public class ButtonListener implements OnClickListener {
        public void onClick(View v) {
            if (!canClicked) {
                return;
            }
            mHandler.sendEmptyMessage(NEXT_IMG);
        }
    }

    public class SwitchHandler extends Handler {
        public void handleMessage(Message paramMessage) {
            if (paramMessage.what == NEXT_IMG) {
                UpdateCurrentBackground();
            }
        }
    }

    private void Set_lollipop_main_Background() {
        Log.d(LOG_TAG, "Set_lollipop_main_Background()");
        mWm = WallpaperManager.getInstance(this);
        mlollipop_main.setBackgroundDrawable(mWm.getDrawable());
    }

    private void UpdateCurrentBackground() {
        Bitmap swBitmap = null;
        if (loopIndex > 5) {
            loopIndex = loopIndex % 6;
        }
        switch (loopIndex) {
        case 0:
            swBitmap = readBitMap(this, R.drawable.loop0);
            mBgImage.setImageBitmap(swBitmap);
            loopIndex++;
            break;
        case 1:
            swBitmap = readBitMap(this, R.drawable.loop1);
            mBgImage.setImageBitmap(swBitmap);
            loopIndex++;
            break;
        case 2:
            swBitmap = readBitMap(this, R.drawable.loop2);
            mBgImage.setImageBitmap(swBitmap);
            loopIndex++;
            break;
        case 3:
            swBitmap = readBitMap(this, R.drawable.loop3);
            mBgImage.setImageBitmap(swBitmap);
            loopIndex++;
            break;
        case 4:
            swBitmap = readBitMap(this, R.drawable.loop4);
            mBgImage.setImageBitmap(swBitmap);
            loopIndex++;
            break;
        case 5:
            swBitmap = readBitMap(this, R.drawable.loop5);
            mBgImage.setImageBitmap(swBitmap);
            loopIndex++;
            break;
        // case 6:
        // mBgImage.setImageResource(R.drawable.loop6);
        // loopIndex++;
        // break;
        default:
            break;
        }
    }

    /**
     * 以最省内存的方式读取本地资源的图片
     * 
     * @param context
     * @param resId
     * @return
     */
    public static Bitmap readBitMap(Context context, int resId) {
        BitmapFactory.Options opt = new BitmapFactory.Options();
        opt.inPreferredConfig = Bitmap.Config.RGB_565;
        opt.inPurgeable = true;
        opt.inInputShareable = true;
        // 设置该属性可获得图片的长宽等信息,但是避免了不必要的提前加载动画
        opt.inJustDecodeBounds = false;
        // 获取资源图片
        InputStream is = context.getResources().openRawResource(resId);
        Bitmap bitmap = BitmapFactory.decodeStream(is, null, opt);

        try {
            is.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return bitmap;
    }

    @Override
    protected void onStop() {
        super.onStop();
        System.gc(); // 提醒系统及时回收
        Log.d(LOG_TAG, "onStop()");
    }

    private void getFrameAndDuration(final Context context, final int animId) {
        // TODO get every frame and its duration

        new Thread(new Runnable() {
            @Override
            public void run() {

                XmlResourceParser parser = context.getResources()
                        .getXml(animId);
                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++) {
                                    Log.d(LOG_TAG,
                                            "getFrameAndDuration() attr="
                                                    + parser.getAttributeName(i)
                                                    + " value="
                                                    + parser.getAttributeValue(i));
                                    if (parser.getAttributeName(i).equals(
                                            "drawable")) {
                                        String imgStr = parser
                                                .getAttributeValue(i)
                                                .substring(1, 11);
                                        int resId = Integer.parseInt(imgStr);
                                        image_resource[initCount] = resId;
                                    } else if (parser.getAttributeName(i)
                                            .equals("duration")) {
                                        duration = parser.getAttributeIntValue(
                                                i, 1000);
                                        image_duration[initCount] = duration;
                                    }
                                }
                                initCount++;
                            }
                        } 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();
                }
            }
        }).start();
    }

    private void loadBitmap(ImageView imageView, int[] resIds, int[] interval) {
        AnimationDrawable clipDrawable = new AnimationDrawable();
        for (int i = 0; i < resIds.length; i++) {
            clipDrawable.addFrame(new BitmapDrawable(readBitMap(this, resIds[i])), interval[i]);
        }

        clipDrawable.setOneShot(true);
        animationDrawable = clipDrawable;
        imageView.setImageDrawable(animationDrawable);
    }
}

 

可以用了, 但感觉好像挺麻烦的, 而且有种东拼西凑的感觉, 如果有更好的方法,或这些代码有什么问题,麻烦告诉我。

参考:

http://blog.csdn.net/xuefu_78/article/details/51908647

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
Android 平台上使用 Animator 创建逐帧动画可以通过以下步骤实现: 1. 首先,在 res/drawable 目录下创建一个 XML 文件来定义您的动画序列,例如: ```xml <animation-list xmlns:android="http://schemas.android.com/apk/res/android" android:oneshot="false"> <item android:drawable="@drawable/frame1" android:duration="100"/> <item android:drawable="@drawable/frame2" android:duration="100"/> <item android:drawable="@drawable/frame3" android:duration="100"/> <item android:drawable="@drawable/frame4" android:duration="100"/> <item android:drawable="@drawable/frame5" android:duration="100"/> </animation-list> ``` 上述代码定义了一个包含 5 帧动画动画序列,每一帧的持续时间为 100ms。 2. 在您的 Activity 中,使用以下代码来加载动画并将其应用到 ImageView 上: ```java ImageView imageView = findViewById(R.id.imageView); AnimationDrawable animation = (AnimationDrawable) getResources().getDrawable(R.drawable.my_animation); imageView.setImageDrawable(animation); animation.start(); ``` 上述代码中,我们首先通过 findViewById 方法获取了 ImageView 控件的实例,然后通过 getResources().getDrawable 方法加载了我们在第一步中定义的动画序列,并将其设置为 ImageView 的背景。最后,我们调用了动画的 start 方法来启动动画。 以上就是使用 Animator 创建逐帧动画的基本步骤。您可以根据自己的需要对动画序列进行修改和扩展。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值