Android-日常遭遇-帧动画oom处理篇

项目遭遇

实现帧动画,我一开始想到的是直接通过animation-list将全部图片按顺序放入,并设置时间间隔和播放模式。然后将该drawable设置给ImageView,然后就可以了

<?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/score_6" android:duration="80"/>
<item android:drawable="@drawable/score_9" android:duration="80"/>
<item android:drawable="@drawable/score_13" android:duration="80"/>
<item android:drawable="@drawable/score_19" android:duration="80"/>
<item android:drawable="@drawable/score_22" android:duration="80"/>
<item android:drawable="@drawable/score_23" android:duration="80"/>
<item android:drawable="@drawable/score_24" android:duration="80"/>
</animation-list>
后来事情也正如所料的一样,完美加载出来了
AnimationDrawable animationDrawable;
if (imageView.getDrawable() == null) {
     imageView.setImageResource(R.drawable.score_anim);
     animationDrawable =(AnimationDrawable)imageView.getDrawable();
}
animationDrawable.start();//开始
animationDrawable.stop();//结束 

但是到了后面,我工程的多个地方需要加载动画,发现直接oom.查看源码发现,是一次导入全部图片才会产生.

然后对源码的动画加载机制进行优化.

然后还做了一系列的封装.这其中,into的时候,会默认加载第一帧,在initDrawableList的时候,第一个参数就是动画的时间.第二个参数是动画资源的数组.我做了可变参数的处理

AnimationManager animationManager = AnimationManager.getInstance().initDrawableList(80,
                                R.drawable.score_0,
                                R.drawable.score_1,
                                R.drawable.score_2,
                                R.drawable.score_3,
                                R.drawable.score_4,
                                R.drawable.score_5,
                                R.drawable.score_6,
                                R.drawable.score_7,
                                R.drawable.score_8,
                                R.drawable.score_9,
                                R.drawable.score_11,
                                R.drawable.score_12,
                                R.drawable.score_13,
                                R.drawable.score_14,
                                R.drawable.score_15,
                                R.drawable.score_16,
                                R.drawable.score_17,
                                R.drawable.score_18,
                                R.drawable.score_19,
                                R.drawable.score_20,
                                R.drawable.score_21,
                                R.drawable.score_22,
                                R.drawable.score_23,
                                R.drawable.score_24,
                                R.drawable.score_25
                        ).into(close);
                        animationManager.start();

这样就非常完美的播放出帧动画,并且不会有内存溢出的出现.这边采用了rxjava处理,如果项目不使用,则可以改成线程和切换线程的处理方式.

附上AnimationManager源码

public class AnimationManager {

    private static AnimationManager sAnimationManager;
    private Handler mHandler = new Handler(Looper.getMainLooper());
    private long  fps;
    private int[] res;
    private int   oneImage;
    private int count  = 1;
    private int length = 0;
    private ImageView  intoView;
    private Bitmap     nextBitmap;
    private Bitmap     currentBitmap;
    private Disposable mSubscribe;

    private AnimationManager() {
    }

    public static AnimationManager getInstance() {
        if (sAnimationManager == null) {
            sAnimationManager = new AnimationManager();
        }
        return sAnimationManager;
    }

    public AnimationManager initDrawableList(long fps, int... Res) {
        this.fps = fps;
        this.res = Res;
        count = 1;
        if (Res.length == 0) {
            throw new RuntimeException("不能是空数组");
        }
        this.oneImage = Res[0];
        length = Res.length;
        return this;
    }

    public AnimationManager into(ImageView view) {
        this.intoView = view;
        // 加载第一张
        Observable.just(oneImage)
                .observeOn(Schedulers.io())
                .map(new Function<Integer, Bitmap>() {
                    @Override
                    public Bitmap apply(Integer integer) throws Exception {
                        BitmapFactory.Options opts = getOptions(integer);
                        // 加载下一张
                        if (res.length > 1) {
                            nextBitmap = BitmapFactory.decodeResource(intoView.getResources(), res[count++], opts);
                        }
                        return BitmapFactory.decodeResource(intoView.getResources(), integer, opts);
                    }
                })
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Consumer<Bitmap>() {
                    @Override
                    public void accept(Bitmap bitmap) throws Exception {
                        intoView.setImageBitmap(bitmap);
                    }
                });
        return this;
    }

    @NonNull
    private BitmapFactory.Options getOptions(Integer integer) {
        /**
         * 先获取图片的和IamgeView各自的宽高
         */
        BitmapFactory.Options opts = new BitmapFactory.Options();
        //给opts配置只获取图片的元数据
        opts.inJustDecodeBounds = true;
        //注意:由于配置了opts并且是仅仅获取图片边界的属性,因此该方法返回的对象永远为null
        BitmapFactory.decodeResource(intoView.getResources(), integer, opts);
        //从opts对象上获取图片的宽高
        int width  = opts.outWidth;
        int height = opts.outHeight;

        int width1 = ScreenUtils.getScreenWidth(intoView.getContext());
        int height1 = ScreenUtils.getScreenHeight(intoView.getContext());

        int sampleSize = Math.max(width / width1, height / height1);


        opts.inJustDecodeBounds = false;//必须配置为加载图片,而不是仅仅获取图片的尺寸
        opts.inSampleSize = sampleSize; //配置等比例缩放的倍数
        return opts;
    }

    public synchronized void start() {
        mSubscribe = Observable.interval(fps, TimeUnit.MILLISECONDS)
                .observeOn(Schedulers.io())
                .map(new Function<Long, Boolean>() {
                    @Override
                    public Boolean apply(Long aLong) throws Exception {
                        count++;
                        if (nextBitmap != null) {
                            currentBitmap = nextBitmap;
                        }
                        if (count > res.length - 1) {
                            return false;
                        }
                        BitmapFactory.Options opts = getOptions(res[count]);
                        nextBitmap = BitmapFactory.decodeResource(intoView.getResources(), res[count], opts);
                        return true;
                    }
                })
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Consumer<Boolean>() {
                    @Override
                    public void accept(Boolean flag) throws Exception {
                        if (flag) {
                            intoView.setImageBitmap(currentBitmap);
                        } else {
                            mSubscribe.dispose();
                        }

                    }
                });

    }
}

猜你喜欢

转载自blog.csdn.net/ci250454344/article/details/82800520