YY项目之帧动画(一)中我们介绍了帧动画的基本使用。
但是如果美工给我们的图片都是几百 * 几百的,加载进不同的分辨率的手机中,占用的内存是显而易见的。
而且,在我的项目中,会经常出现OOM,所以下面就来解决由帧动画引起的OOM问题。
由前面的文章可以知道,这个需求主要实现framelayout的上面一层来实现动画,底下的层用来实现需要展示的视图。
所以,底下的视图层照常编辑即可。
如果需要解决帧动画加载内存占用的问题,就不能加载编辑好的drawable文件夹中的xml文件了,需要手动编辑java代码,在java代码层面处理生成AnimationDrawable(这里是关键的思想)。
使用java代码创建AnimationDrawable的好处是:动态的按需处理加载进内存的图片的像素,从而优化了内存占用过多(甚至发生OOM)的问题。
那么,接下来,就看看代码是如何实现的吧,只列举其中的一个AnimationDrawable动画。
手动创建AnimationDrawable,并设置到指定的View上
/** * 初始化 点击的动画 */ clickDrawable = new AnimationDrawable(); clickDrawable.setOneShot(true); for (int i = 0 ;i < 9 ;i++) { if (i == 0 || i == 8) { // 添加透明的帧 clickDrawable.addFrame(getResources().getDrawable(R.drawable.transpanrent), 50); } else { int resId = getResources().getIdentifier("click_" + (i - 1), "mipmap", getPackageName()); clickDrawable.addFrame(new BitmapDrawable(getResources(), ImageLoaderUtils.decodeSampledBitmapFromResource(getResources(), resId, 100, 100)), 50); } } iv_anim.setImageDrawable(clickDrawable);
里面需要用到的透明的效果的xml文件:
<?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle"> <solid android:color="@android:color/transparent"/> <stroke android:color="@android:color/transparent"/> </shape>
设置点击事件,执行动画:
iv_click.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (right) { if (!isLongClick) { restartAnimation(clickDrawable); } } else { // 显示红色背景 showWrong(); } } });
关键代码片段:
/** * 重新启动动画 * 首先得停止帧动画,然后才能重新执行帧动画,否则没有效果 * * @param drawable */ private void restartAnimation(AnimationDrawable drawable) { if (drawable.isRunning() && drawable != null) { drawable.stop(); } drawable.start(); }
ImageLoaderUtils 解决该问题的关键方法源码:
/** * 计算图片的缩放比例 <br/> * 作者 :dengjie zhang <br/> * created at 2016/3/16 9:25 */ public static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) { // 源图片的高度和宽度 final int height = options.outHeight; final int width = options.outWidth; int inSampleSize = 1; if (height > reqHeight || width > reqWidth) { // 计算出实际宽高和目标宽高的比率 final int heightRatio = Math.round((float)height / (float)reqHeight); final int widthRatio = Math.round((float)width / (float)reqWidth); // 选择宽和高中最小的比率作为inSampleSize的值,这样可以保证最终图片的宽和高 // 一定都会大于等于目标的宽和高。 inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio; } return inSampleSize; } /** * 获取合适的大小的图片的bitmap的形式 <br/> * 作者 :dengjie zhang <br/> * created at 2016/3/16 9:27 */ public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId, int reqWidth, int reqHeight) { // 第一次解析将inJustDecodeBounds设置为true,来获取图片大小 final BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; BitmapFactory.decodeResource(res, resId, options); // 调用上面定义的方法计算inSampleSize值 options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight); // 使用获取到的inSampleSize值再次解析图片 options.inJustDecodeBounds = false; return BitmapFactory.decodeResource(res, resId, options); }