当前位置: 首页 > news >正文

[04] Android逐帧动画(一)

链接:http://developer.android.com/reference/android/graphics/drawable/AnimationDrawable.html

     http://developer.android.com/reference/android/graphics/drawable/DrawableContainer.html

 

  在项目中实现一个欢迎页的逐帧动画(100张图,每张图片约3K大小,播放时间2.5秒),尝试了五种方法,都不能满足要求:

  1. 使用 AnimationDrawable加载逐帧动画;

  2. 使用 VideoView播放.3gp文件;

  3. 使用 WebView加载.gif图片;

  4. 使用 WebView播放 flash;

  5. 自定义一个带图片回收机制的 View逐帧加载图片。

 

 

  过程中遇到的问题及分析如下:

 

  1. AnimationDrawable:图片过多,总的占用内存很大,导致 OOM异常。

  在网上有很多简单的例子介绍 AnimationDrawable的用法,都是在 res/drawable下写一个帧序列,然后通过一个 ImageView对象把这个 Drawable作为背景或是图片资源加载出来。看 AnimationDrawable类的逐帧实现方法我们就可以发现,Android系统是把这些图片都预加载出来的。AnimationDrawable类中逐帧动画调用的方法依次是:start() - run() - nextFrame() - setFrame() - selectDrawable()...

    public boolean selectDrawable(int idx) {
        if (idx == mCurIndex) {
            return false;
        }

        final long now = SystemClock.uptimeMillis();

        if (DEBUG) android.util.Log.i(TAG, toString() + " from " + mCurIndex + " to " + idx
                + ": exit=" + mDrawableContainerState.mExitFadeDuration
                + " enter=" + mDrawableContainerState.mEnterFadeDuration);

        if (mDrawableContainerState.mExitFadeDuration > 0) {
            if (mLastDrawable != null) {
                mLastDrawable.setVisible(false, false);
            }
            if (mCurrDrawable != null) {
                mLastDrawable = mCurrDrawable;
                mExitAnimationEnd = now + mDrawableContainerState.mExitFadeDuration;
            } else {
                mLastDrawable = null;
                mExitAnimationEnd = 0;
            }
        } else if (mCurrDrawable != null) {
            mCurrDrawable.setVisible(false, false);
        }

        if (idx >= 0 && idx < mDrawableContainerState.mNumChildren) {
            Drawable d = mDrawableContainerState.mDrawables[idx];
            mCurrDrawable = d;
            mCurIndex = idx;
            if (d != null) {
                d.mutate();
                if (mDrawableContainerState.mEnterFadeDuration > 0) {
                    mEnterAnimationEnd = now + mDrawableContainerState.mEnterFadeDuration;
                } else {
                    d.setAlpha(mAlpha);
                }
                d.setVisible(isVisible(), true);
                d.setDither(mDrawableContainerState.mDither);
                d.setColorFilter(mColorFilter);
                d.setState(getState());
                d.setLevel(getLevel());
                d.setBounds(getBounds());
            }
        } else {
            mCurrDrawable = null;
            mCurIndex = -1;
        }

        if (mEnterAnimationEnd != 0 || mExitAnimationEnd != 0) {
            if (mAnimationRunnable == null) {
                mAnimationRunnable = new Runnable() {
                    @Override public void run() {
                        animate(true);
                        invalidateSelf();
                    }
                };
            } else {
                unscheduleSelf(mAnimationRunnable);
            }
            // Compute first frame and schedule next animation.
            animate(true);
        }

        invalidateSelf();

        return true;
    }

在 selectDrawable()方法里,可以看到每一帧的加载,都是从 Drawable数组里找出当前序号对应的 Drawable对象(因为 AnimationDrawable类本身继承自 DrawableContainer类),然后把这个 Drawable对象设置为可见。Android没有提供回调或函数能让我们在每加载完一帧后都清理掉之前的图片,所以会出现 OOM的问题。

 

  2. VideoView播放3gp文件:VideoView背景色适配问题。

  同样的一段代码,在不同的手机上,可以看到 VideoView背景色值并不是整个 Activity的背景色。显示效果比较难看。

   VideoView videoView = (VideoView) findViewById(R.id.video);
   videoView.setBackgroundColor(Color.TRANSPARENT);
   videoView.setVideoURI(Uri.parse("android.resource://com.example.android/" + R.raw.frames));
   videoView.setMediaController(new MediaController(MainActivity.this));
   videoView.start();

 

  3. WebView加载 gif图片:图片模糊。

  gif格式的图片最多只能有256种色值,如果把100张图片用 Flash导出成一整张 gif图片,会有很多小黑点,原因就是不在那256个基础色值的像素点都会显示成黑色。现在手机的屏幕尺寸、分辨率都越来越大,使用 gif格式的图片不能满足视觉要求。

 

  4. WebView播放 flash:需要插件支持。

  目前 Android和 Adobe搞不到一起,用户需要下载 Adobe Flash Player才能在手机上看.flv,H5的<video>标签也需要浏览器的 Flash插件支持。

 

  5. 自定义控件逐帧加载图片:手机处理速度跟不上。

  思路是这样的:以当前图片为中心向后预加载5帧(即维持缓存中最多保留5个 Bitmap对象,防止 OOM出现),比如当前是第20帧,那么缓存里应该有20-24这5帧的图片。然后每加载一帧,就在后台线程 recycle一张旧的 bitmap并 decode一张新的 bitmap。

  但是.. BitmapFactory.decodeResource()执行速度跟不上...

  100张图,2.5秒,即两帧间隔是25ms,在组里的十几个 Android手机上,最快的手机单线程执行BitmapFactory.decodeResource()方法也需要40ms左右,平均是70ms。比如现在要加载第6帧,这帧对应的 bitmap应该是加载完成第1张后开始 decode的,没法保证在第5帧跳转到第6帧的时候,这个 bitmap一定能够 decode完成。当然可以通过增加缓存的帧数和延长两帧间的间隔实现,但这么做并不保险,因为手机性能与多线程管理的差异,我们并不能确保 decode操作开始执行的时间与实际执行的时长,并且1秒24帧,是效果连续的最低要求。

  这让我想到小时候做的脑残应用题——池塘里有两根水管,一个加水一个放水,放水的速度是加水的3倍...

 

  

  以上是这5种方法遇到的问题,在帧数较少并且每一帧图片尺寸不大的情况下,AnimationDrawable是首选。安装有 Flash插件的情况下,可以把逐帧动画导出成一个.flv文件,播放效果好于.3gp文件或是 gif图片。

  既然使用 Video可以加载视频,并且不出现 OOM,那么 Android系统上肯定有方法能够实现高清、连续的逐帧动画实现方法。

 

 

 

转载于:https://www.cnblogs.com/haitong/p/3509199.html

相关文章:

  • Android 4.0新特性:拍照和拍视频可以收到广播了
  • (三) diretfbrc详解
  • @selector(..)警告提示
  • Buffer Pool--内存相关术语
  • Java程序员应该了解的10个设计原则
  • GridControl 设置焦点单元格
  • java常量池
  • 【iCore2 模块相关资料】发布模块DEMO 代码包,目前支持 iM_TFT30、 iM_LAN和 iM_RGB 三个模块...
  • 【基础】Oracle 表空间和数据文件
  • poj1195
  • PHP Install in IIS
  • mongoDB研究笔记:复制集故障转移机制
  • 网络资源收集
  • (顺序)容器的好伴侣 --- 容器适配器
  • javascript实现自动关闭的alert对话框
  • 【跃迁之路】【641天】程序员高效学习方法论探索系列(实验阶段398-2018.11.14)...
  • 77. Combinations
  • Android框架之Volley
  • Cookie 在前端中的实践
  • echarts的各种常用效果展示
  • ES6核心特性
  • exif信息对照
  • fetch 从初识到应用
  • github从入门到放弃(1)
  • k8s如何管理Pod
  • October CMS - 快速入门 9 Images And Galleries
  • SQLServer之创建显式事务
  • Three.js 再探 - 写一个跳一跳极简版游戏
  • underscore源码剖析之整体架构
  • Web标准制定过程
  • 包装类对象
  • 从0搭建SpringBoot的HelloWorld -- Java版本
  • 从tcpdump抓包看TCP/IP协议
  • 技术胖1-4季视频复习— (看视频笔记)
  • 理解IaaS, PaaS, SaaS等云模型 (Cloud Models)
  • 前端技术周刊 2019-01-14:客户端存储
  • 人脸识别最新开发经验demo
  • 微信小程序上拉加载:onReachBottom详解+设置触发距离
  • 要让cordova项目适配iphoneX + ios11.4,总共要几步?三步
  • Android开发者必备:推荐一款助力开发的开源APP
  • LevelDB 入门 —— 全面了解 LevelDB 的功能特性
  • 哈罗单车融资几十亿元,蚂蚁金服与春华资本加持 ...
  • #NOIP 2014# day.1 T2 联合权值
  • #pragma data_seg 共享数据区(转)
  • #Ubuntu(修改root信息)
  • #微信小程序:微信小程序常见的配置传值
  • (003)SlickEdit Unity的补全
  • (2009.11版)《网络管理员考试 考前冲刺预测卷及考点解析》复习重点
  • (42)STM32——LCD显示屏实验笔记
  • (十六)Flask之蓝图
  • (一)u-boot-nand.bin的下载
  • (已解决)什么是vue导航守卫
  • (转)总结使用Unity 3D优化游戏运行性能的经验
  • (轉貼) 蒼井そら挑戰筋肉擂台 (Misc)
  • .bashrc在哪里,alias妙用