Android 用surfaceview模拟帧动画的效果,解决帧动画的OOM问题

利用SurfaceView实现帧动画效果,更流畅,更节约内存 利用SurfaceView实现帧动画效果 在开发Android做动画效果的时候,有时候UI给开发一组动画实现的帧图片,如果说图片较少(十几张)、分辨率较低(几K,十几K),用帧动画实现应该没什么问题,但是如果有几十上百张、或者几百K或者上M的图片,这个时候用帧动画来实现其实就很有问题了,内存吃紧,会卡顿,OOM等问题随之而来。 当然如果可以沟通UI改设计是最好的,但是如果非得这样做不可呢?本人就遇... 阅读详情

最近做的项目,客户临时要求改版,我真的是最烦这个,要求跟换主页面的背景,换上新的背景图,要求是动态的。

效果(我随便拿的五个图片做的gif):



方案:

帧动画方案:

        缺点:1.好像只能imageview才能播放帧动画 

                2.容易OOM(播三四张还行,播九十张以上,且,每张都在300k左右就有OOM问题)

                3.看到网上方案解决帧动画OOM,是一次播放十张,再往里面添十张,再播放。问题就有了,动画有一个                      添加十个图片的时间卡顿。


surfaceview方案:

         因为imageview要是以一张一张换,性能必定不如surfaceview。核心应该是

      canvas = surfaceHolder.lockCanvas(rect);
      canvas.drawBitmap(lruCache.get(folderName + "/" + assets[position]), null, rect, null);
        我把上百张的图片放在assets文件夹下,然后读取图片(这边可以做Lrucache优化),下边贴出我的代码:

        surfaceHolder = sv_main.getHolder();
        lruCache = new StringBitmapLruCache();
        surfaceHolder.addCallback(new SurfaceHolder.Callback() {
            @Override
            public void surfaceCreated(SurfaceHolder holder) {

            }

            @Override
            public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {


                rect = new Rect(0, 0, width, height);

                //获取主题
                SharedPreferences sp = getSharedPreferences("setting", Context.MODE_PRIVATE);
                String theme = sp.getString("theme", "bgone");
                switch (theme) {
                    case "bgone":
                        folderName = "bgone";
                        break;
                    case "bgtwo":
                        folderName = "bgtwo";
                        break;
                    case "bgthree":
                        folderName = "bgthree";
                        break;
                }

                try {
                    assetManager = getAssets();
                    assets = assetManager.list(folderName);
                    totalCount = assets.length;
                    if (lruCache.get(folderName + "/" + assets[0]) == null) {
                        Bitmap bitmap = BitmapFactory.decodeStream(assetManager.open(folderName + "/" + assets[0]));
                        lruCache.put(folderName + "/" + assets[0], bitmap);
                    }
                    canvas = surfaceHolder.lockCanvas(rect);
                    canvas.drawBitmap(lruCache.get(folderName + "/" + assets[0]), null, rect, null);
                    holder.unlockCanvasAndPost(canvas);

                    if (!isFlag) {
                        startDecodeThread();
                        isFlag = true;
                    }


                } catch (IOException e) {
                    e.printStackTrace();
                }

                isFlag = true;


            }

            @Override
            public void surfaceDestroyed(SurfaceHolder holder) {
                RxUtils.unsubscribe(animationSub);
            }
        });

 private void startDecodeThread() {

        RxUtils.unsubscribe(animationSub);
        animationSub = Observable.interval(200, TimeUnit.MILLISECONDS).subscribeOn(Schedulers.io()).subscribe(new Subscriber<Long>() {
            @Override
            public void onCompleted() {

            }

            @Override
            public void onError(Throwable e) {

            }

            @Override
            public void onNext(Long aLong) {
                Logger.i("DDSSK::" + position);
                if (position >= totalCount) {
                    position = 0;
                }

                canvas = surfaceHolder.lockCanvas(rect);
                // if (canvas != null) {

                canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
                if (lruCache.get(folderName + "/" + assets[position]) == null) {
                    try {
                        Bitmap bitmap = BitmapFactory.decodeStream(assetManager.open(folderName + "/" + assets[position]));
                        lruCache.put(folderName + "/" + assets[position], bitmap);
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                canvas.drawBitmap(lruCache.get(folderName + "/" + assets[position]), null, rect, null);
                surfaceHolder.unlockCanvasAndPost(canvas);


              /*  try {
                    Bitmap bitmap = BitmapFactory.decodeStream(assetManager.open(folderName + "/" + assets[0]));
                    canvas.drawBitmap(bitmap, null, rect, null);
                    surfaceHolder.unlockCanvasAndPost(canvas);

                } catch (IOException e) {
                    e.printStackTrace();
                }*/

                position++;
            }
        });
    }

好,下面讲一下我遇到的坑

1.surfaceview准备的时候,界面是一片黑。所以在surfacechanged的时候我要展示动画的第一张图,这样就不黑了

2.canvas为空?因为canvas是从surfaceview获得的,如果surfaceview没有准备好,它绝对为空

3.如果界面跳转再返回,surfaceview还会创建,但是我点了黑屏再亮屏,surfaceview就不会在创建,动画就播不了,所以要写一个开关,在onresume里写代码触发动画

4.surfaceview的优化,因为播放太多的图片,占用太多资源,导致其他的组件超卡。因为surfaceview可以在子线程跟新UI,所以我们可以起线程轮播图


附件:

package utils;

import android.graphics.Bitmap;
import android.support.v4.util.LruCache;

/**
 * Created by Administrator on 2017/6/23 0023.
 */

public class StringBitmapLruCache extends LruCache<String, Bitmap> {
    public StringBitmapLruCache() {
        // 构造方法传入当前应用可用最大内存的八分之一
        super((int) (Runtime.getRuntime().maxMemory() / 1024 / 8));
    }

    @Override
    // 重写sizeOf方法,并计算返回每个Bitmap对象占用的内存
    protected int sizeOf(String key, Bitmap value) {
        return value.getByteCount() / 1024;
    }

    @Override
    // 当缓存被移除时调用,第一个参数是表明缓存移除的原因,true表示被LruCache移除,false表示被主动remove移除,可不重写
    protected void entryRemoved(boolean evicted, String key, Bitmap oldValue, Bitmap
            newValue) {
        super.entryRemoved(evicted, key, oldValue, newValue);
    }

    @Override
    // 当get方法获取不到缓存的时候调用,如果需要创建自定义默认缓存,可以在这里添加逻辑,可不重写
    protected Bitmap create(String key) {
        return super.create(key);
    }
}

结束语:虽然这个需求是实现了,但造成了另外一个问题,apk过大,因为播放一个主题,就是至少90图,每张300k。我要实现三个主题,那就是五六十M。于是我就在想,当初要是弄成视频文件,我播放视屏的话,既解决了OOM也解决了APK过大的问题。







Android性能优化 _ 大图做帧动画卡?优化帧动画之 SurfaceView滑动窗口式帧复用 } protected abstract void onFrameDraw(Canvas canvas); } //帧动画绘制类:将绘制内容具体化为一张Bitmap public class FrameSurfaceView extends BaseSurfaceView { … private BitmapFactory.Options options; @Override protected void onFrameDraw(Canvas canvas) { clearCanvas(canvas); i 阅读详情

相关推荐

SurfaceView做帧动画

前提条件我就不说了,相信能查找这个主题的都不是一般的Android开发者,我只讲核心的部分和该文章所能解决的问题。 之前搜索过很多文章,大都不理想,无法完美的解决自己的需求,然后自己根据资料整理了一下,可以说非常完美。 解决的问题: 1、帧特别多,如果同时decode做动画可能会出现OOM的情况 2、CPU、内存占用过高 3、可以多次做重复做动画 4、代码精简易懂效率高   废话不...

mzoneseven的专栏 1977

大图做帧动画卡顿?不存在的!—— 优化帧动画之SurfaceView 滑动窗口式帧复用...

继上篇用“SurfaceView逐帧解析 & 帧复用”优化了帧动画内存性能后,一个更复杂的问题浮出水面:帧动画时间性能。这一篇试着让每帧素材大小 1MB 的帧动画流畅播放的同时不让内存膨胀。在整个优化过程中,综合运用了多线程、阻塞队列、消息机制、滑动窗口机制。也体悟到了计算机设计的中庸之道。 在此要感谢评论上一篇文章的掘友“小前锋”,是你的提问指引了我在这个方向上继续探索。 (ps:粗斜体...

weixin_34080571的博客 795

AutoGLM:旧安卓手机离线运行GLM-4的轻量化AI方案

端侧大模型推理是指在终端设备本地完成大型语言模型的加载与计算,无需依赖云端服务。其核心原理在于模型压缩、硬件加速适配与系统级优化,技术价值体现在隐私保护、低延迟响应和离线可用性。典型应用场景包括手写笔记润色、汽车故障诊断、方言健康咨询等对网络稳定性与数据敏感性要求高的边缘任务。AutoGLM正是面向2016–2019年主流旧安卓设备(如麒麟960、骁龙845)设计的INT4量化GLM-4推理框架,深度融合NNAPI与Vulkan调度,并支持Feenote等手写APP无缝联动。

weixin_34026276的博客 2376

使用SurfaceView加载多张大分辨率图片做帧动画,解决OOM问题

项目需求:动态背景 需求很简单,只是用帧动画做一个动态的背景而已,但若是70多张图片都是1920*1080,一张485k的话,传统意义上的帧动画就很难实现了,往往加载10张就开始OOM。 一般来说,常用的实现动态背景的有效方式有三种: ①视频:果断粗暴,清晰度很有保证,但是在无限轮播重复的时候,总会有一瞬间的卡顿,这真的很让人郁闷。 ②GIF动态图:直接

Giousa的博客 4900

金融App模糊效果实战:基于Blurry库的安全与性能优化指南

高斯模糊作为一种常见的图像处理技术,其核心原理是通过卷积运算对像素进行加权平均,从而实现柔化与隐藏细节的视觉效果。在移动开发领域,这一技术常被用于提升UI美观度与营造沉浸感。然而,在金融、银行等对安全与性能有严苛要求的应用场景中,模糊效果的技术价值发生了根本性转变——它从一种视觉装饰升级为关键的安全防护与隐私保护手段。其核心挑战在于平衡算法的实时性、处理过程的内存消耗与最终的信息隐藏效果,确保在防止敏感信息被窥屏或截屏泄露的同时,不影响应用在各类终端设备上的流畅运行。本文以广泛使用的轻量级Android模糊

weixin_30699955的博客 388

Unity与Android混合开发实战:从架构到性能优化的完整指南

移动应用开发中,原生开发与游戏引擎的融合已成为拓展应用能力边界的关键技术。其核心原理在于将高性能的图形渲染引擎作为库模块集成到原生应用中,实现技术栈的优势互补。这种架构的价值在于,开发者可以针对不同功能模块选用最合适的技术方案:原生框架负责处理复杂的业务逻辑、UI交互和深度系统调用,保证应用的流畅度与能效;而Unity等引擎则专注于需要强大图形算力的3D渲染、AR/VR及游戏化交互场景,保障视觉体验与开发效率。在电商、教育、工业仿真等应用场景中,该技术能无缝嵌入3D模型展示、虚拟试穿、沉浸式教学等模块,极大

germmy-神一样的开发 521

Android相机开发进阶:从Camera2 API到性能优化与计算摄影

在移动应用开发中,相机功能是实现图像采集与处理的核心模块,其底层架构涉及硬件抽象层(HAL)、图像信号处理器(ISP)与数据流管道的协同工作。理解相机体系结构的工作原理,有助于开发者优化性能并实现高级特性,例如低延迟预览、多摄像头协同与计算摄影。通过Camera2 API,开发者可以精细控制图像传感器、曝光参数与数据缓冲区,从而在视频通话、AR应用与专业摄影工具等场景中提升用户体验。本文聚焦Android相机开发中的关键组件,如ImageReader与CameraCharacteristics,并探讨如何通

weixin_34013044的博客 465

Flutter与Unity混合开发性能优化实战:从卡顿到丝滑的完整解决方案

在移动应用开发中,混合开发架构常被用于整合不同引擎的优势,例如结合Flutter的跨平台UI能力与Unity的高性能3D渲染。其核心原理在于通过原生层桥接两个独立的运行时环境,实现通信与渲染协同。这种架构的技术价值在于能够打造兼具丰富2D交互与沉浸式3D体验的复合型应用,广泛应用于电商产品展示、教育仿真、AR/VR等场景。然而,性能瓶颈是混合开发面临的主要挑战,尤其是当Flutter与Unity在**视图嵌入**模式下协同工作时,容易出现渲染冲突、内存飙升与通信延迟问题。本文聚焦于通过**纹理传递**优化、

weixin_30920853的博客 359

2026 Android高级工程师 · 大厂面试题库(难度:⭐⭐⭐⭐⭐)

模拟真实面试场景,按轮次展开。覆盖协程状态机、Binder源码、JVM调优、ANR/Native Crash全链路排查,每道题含追问与回答要点。适合冲刺一二线互联网大厂

帅次的博客 1940

Unity全平台PDF渲染插件集成指南:从UI到3D物体的完整解决方案

在跨平台应用开发中,文档渲染与交互是常见的核心技术需求。其原理涉及文件解析、图形光栅化、内存管理与平台原生接口适配等多个底层技术环节。这项技术的核心价值在于,它能够将复杂的文档格式(如PDF)高效、准确地转换为可视化的图形界面元素,同时保持文本可搜索、可复制等原生特性,极大地提升了应用的功能完整性与用户体验。在游戏开发、教育软件、企业工具及AR/VR等应用场景中,实现稳定、高性能的文档展示功能至关重要。本文聚焦于Unity引擎环境,深入探讨如何利用成熟的第三方插件,一站式解决PDF文档的**全平台支持**与

weixin_30512043的博客 359

YOLOv8航拍牧场牛羊识别实战指南

目标检测是计算机视觉的基础任务,其核心在于从图像中准确定位并分类物体;YOLO系列凭借端到端、高效率和强泛化能力,成为工业级实时检测的主流选择。随着边缘计算普及,轻量模型在无人机、嵌入式设备上的部署需求激增,而YOLOv8凭借Anchor-Free设计、Ultralytics简洁API与原生ONNX/TensorRT支持,显著降低落地门槛。在农业智能化场景中,航拍图像因尺度变化大、遮挡严重、光照多变等特点,对模型鲁棒性提出严苛要求;YOLOv8的Task-Aligned Assigner与C2f轻量化结构,

weixin_30745553的博客 382

腾讯开源1.8B轻量翻译模型:1GB内存安卓端实测可用

轻量翻译模型是面向边缘设备与离线场景的关键AI基础设施,其核心在于突破内存墙、带宽墙与算力墙的物理约束。通过结构精简(如GQA替代MHA)、混合量化(INT4+FP16)与动态内存复用等技术路径,可在低至1GB运行内存的Android设备上实现稳定推理。这类模型不仅支撑多语种覆盖与方言适配,更在无网、高隐私、低功耗等真实工业场景中展现工程落地价值。本文聚焦腾讯HY-MT1.5-1.8B开源翻译模型,详解其手机端可部署设计原理与实操验证过程。

weixin_34392435的博客 287

Android在线学习系统开发:MVVM架构与ExoPlayer实战指南

移动应用开发是当前计算机教育与实践的热门领域,其核心在于如何构建稳定、高效且用户体验良好的客户端。MVVM(Model-View-ViewModel)架构模式通过数据驱动的方式,实现了视图与业务逻辑的清晰分离,配合Kotlin协程等现代异步编程技术,能有效提升代码的可维护性和健壮性。这种架构模式在需要处理复杂数据流和状态管理的应用中价值显著,例如在线教育、内容消费等场景。本文聚焦于Android平台,深入探讨如何运用MVVM架构、Room数据库以及ExoPlayer等关键技术,构建一个功能完整的移动终端在线

weixin_32745665的博客 252

Android调用系统相机、自定义相机、处理大图片

Android调用系统相机和自定义相机实例本博文主要是介绍了android上使用相机进行拍照并显示的两种方式,并且由于涉及到要把拍到的照片显示出来,该例子也会涉及到Android加载大图片时候的处理(避免OOM),还有简要提一下有些人SurfaceView出现黑屏的原因。 Android应用拍照的两种方式,下面为两种形式的Demo展示出来的效果。 知识点: 一、调用系统自带的相...

weixin_30794491的博客 89

机械臂学习:视觉引导——绪论

视觉引导 = 定位 + 引导定位:视觉系统定位到待引导的物体引导:视觉系统引导机械臂按需要的轨迹实现一定的工艺流程(过度点:人为指定机械臂的轨迹防止碰撞)(点云匹配:解决位姿估计姿态估计的问题)无序抓取的三个核心技术:3d识别(图中的点云匹配) 抓取方法路径规划(防止机械臂的碰撞,如自身碰撞等)如果只有同一高度的平移和旋转,其实并不需要点云,用单目就可以做,但是如果涉及到物体的倾斜以及高度的变换,那就是单目力所不能及,所以就是第三种情况:平移旋转加垫高。

2303_80018785的博客 4042

DIY天文摄影:如何用NMP溶剂安全去除佳能CMOS传感器的拜耳滤镜(附详细步骤)

本文为天文摄影爱好者提供了一份详尽的DIY指南,介绍如何使用NMP溶剂安全去除佳能CMOS传感器的拜耳滤镜,将其改造为高灵敏度单色相机。文章深入剖析了NMP溶剂的作用原理与关键风险,并系统性地拆解了从材料准备、分步操作到后期验证的完整实践流程,旨在帮助具备动手能力的爱好者实现深空天体摄影的进阶目标。

w3x4y的博客 306

Android相机Overlay叠加层:基于CameraX的自定义View绘制网格与水印

在移动端相机开发中,Overlay叠加层是构建贴纸、水印、扫码框及增强现实效果的核心机制。其本质并非修改底层像素,而是通过“相机预览画面+实时绘制层”的两层模型实现视觉合成。理解这一原理后,开发者无需迷信OpenGL,借助Android系统View层或硬件加速的GLSurfaceView即可完成轻量级叠加能力。本文以CameraX为相机预览方案,通过自定义OverlayView在预览画面中绘制参考网格与动态水印,完整演示了从环境配置、布局层级控制、坐标旋转适配到运行验证的工程流程。Overlay技术广泛应用

weixin_34405557的博客 330

golang 线上事故

golang 线上事故 最近公司要做大促的一些活动。并且单量,qps持续上涨。之前使用的是django python 语言做的一个服务端。目前已经部署的国家里面最多的国家会有300+个实例。大促期间还可能会增加一个实例数。这么多的实例部署,回滚的时间都会特变长,除了问题也不好定位。并且如此多的一个机器,连接数* 实例数也会导致DB等其他服务扛不住这么大的并发。所以决定上go服务解决性能问题。 ...

lcf枫的博客 1537

Android中高级面试核心能力与Kotlin高级特性解析

在移动开发领域,Android工程师的技术能力评估往往围绕系统架构设计、性能优化和语言特性掌握展开。Kotlin作为Android官方推荐语言,其协程机制通过结构化并发模型显著提升了异步编程效率,而Flow则实现了响应式数据流的线程安全处理。这些技术不仅优化了内存管理和CPU利用率,更在电商、社交等高并发场景中展现出关键价值。本文以面试视角剖析中高级开发者必备的Binder通信原理、View渲染优化等Framework层知识,同时详解Kotlin协程的withTimeout控制、Channel热数据流等实战

cuiji1279的博客 342

迈德威视相机调用( 基于 Linux系统+ OpenCV )

迈德威视相机调用( 基于 Linux系统+ OpenCV )前言一、登录迈德威视官网,下载官方SDK二、代码调用与视频帧处理( 基于 OpenCV )总结 前言     此博客记录了迈德威视工业相机在 Linux 系统下的代码调用及其环境配置,通过 OpenCV 对视频帧进行处理。   一、登录迈德威视官网,下载官方SDK      迈德威视官网 : http://www.mindvision.com.cn/     1. 进入官网后,在服务支持中选择软件下载。    2. 选择Linux系统S.

kkkkkk0729的博客 5675

从想法到零件:手把手拆解一个汽车功能如何从PRD写到SSTS和CTS

本文详细拆解了汽车电子需求从市场文档(MRD)到零部件技术规范(CTS)的完整流程,以雨天自动关窗功能为例,展示了PRD、SSTS和CTS的编写要点与交互设计。文章重点解析了系统分解的艺术和零部件落地的精确参数要求,为汽车电子工程师提供了从概念到实现的全流程实践指南。

weixin_30300225的博客 480

AndEngine与Cocos2d-x深度对比:2D游戏引擎选型实战指南

在移动游戏开发中,游戏引擎是构建项目的核心框架,其架构设计直接决定了开发效率与最终性能表现。引擎通过封装底层图形API(如OpenGL ES)和提供场景管理、物理模拟等模块,简化了游戏开发流程。理解引擎的渲染原理、内存管理机制和跨平台实现方式,对于优化游戏性能、避免常见问题(如Cocos2d游戏黑屏)至关重要。从技术价值看,合适的引擎能降低开发成本,提升代码可维护性,并保障项目长期稳定运行。在2D手游、微信小游戏等应用场景中,开发者常面临在轻量级原生引擎与功能丰富的跨平台引擎间的抉择。本文聚焦于AndEng

weixin_33675507的博客 376

使用【阿里云百炼】搭建自己的大模型

本文介绍阿里云百炼大模型平台,其为企业级服务平台,融合通义千问等模型,支持多模态能力,提供一站式工具降低开发门槛。重点讲解智能体应用及大模型搭建步骤,含进入创新应用界面、选模型配参数、输指令、导数据、加载知识库、获取API Key、加样例库、配置MCP,还提及模型调试与多平台发布,并附试用链接,助力企业与开发者快速搭建适配业务的AI模型。

Larry的博客 4738

移动端实时AI换脸部署实战:模型量化与跨平台优化

模型量化是移动端AI部署的核心技术之一,它通过降低模型权重和激活值的数值精度(如从FP32到INT8),在可接受的精度损失范围内,大幅减少模型体积和计算量。其原理在于利用整数运算的高效性和移动端芯片的专用硬件加速单元,从而显著提升推理速度并降低内存带宽需求。这项技术的工程价值在于,它使得原本只能在云端或高性能PC上运行的复杂视觉AI模型,得以在资源受限的移动设备上实现实时推理。在实时换脸、图像增强、AR特效等移动端AI应用场景中,模型量化结合跨平台推理框架(如Core ML、TFLite),是解决算力、内存

410

PTPX功耗分析实战——从脚本配置到报告解读

本文详细介绍了PTPX功耗分析的全流程,从脚本配置到报告解读,帮助工程师快速掌握芯片设计中的功耗估算技术。文章涵盖了环境搭建、波形文件处理、功耗报告解析等关键环节,并提供了实战经验和优化建议,特别适合需要提升PTPX功耗分析效率的开发者。

weixin_29248313的博客 279

YOLO26剪枝 lamp剪枝测试精度仅掉0.7个点,速度提高11.8fps!

针对没有如何去选择剪枝的内容LAMP是层自适应幅度调整剪枝,无需任何参数,通过算法内部自己计算每个层的重要程度进行剪枝。基于权重重要程度和该层权重大小关系,权重越大表明该层越重要的思想进行优化。这个跟我前面说的非结构化全局剪枝是一个解法(MP),也就是lamp是在我前面那个非结构化剪枝的基础上进行优化的。但是这个逐层进行非结构剪枝目前还没有一个清晰的概念,确定每个层要剪枝多少。LAMP得分是一个平方权重大小,由层中所有“幸存权重”的总和归一化。

m0_64661770的博客 673
上一篇: Android SurfaceView+MediaPlayer 本地视频播放器
下一篇: Android 椭圆轨迹动画
泡温泉的咸鱼
博客等级 码龄11年 39粉丝 48原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值