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

安卓demo-壁纸预览、分屏小窗与U盘播放时长记忆功能

壁纸预览1.背景有的项目需要做壁纸功能就会用到壁纸预览功能。类似于手机上的壁纸预览功能选择图片-点击预览-桌面上的组件、应用图片名称等会出现在壁纸上。图1.实际桌面与壁纸预览界面2.现状分析现在桌面已经做成一个应用了覆盖在原生的桌面上不再走原生的wallpaper因此通过原生的wallpaper设置或获取壁纸属性不会生效。3.可行性方案让负责桌面开发的同事在预览壁纸开始前把桌面主界面的view组件进行截图传给负责预览功能的同事该同事再将需要预览的图片与截好的图进行叠加完成预览功能。流程如图1所示图2. 使用view截图完成壁纸预览功能流程图4.view的组件的截图关键代码private void screenShoot() { // 获取当前屏幕的组件截图 View rootView getActivity().getWindow().getDecorView().getRootView(); rootView.setDrawingCacheEnabled(true); Bitmap screenshot viewShot(ll_main_view); rootView.setDrawingCacheEnabled(false); // 将截图保存到文件 String imagePath Environment.getExternalStorageDirectory() /screenshot.png; FileOutputStream fos null; try { fos new FileOutputStream(imagePath); screenshot.compress(Bitmap.CompressFormat.PNG, 100, fos); fos.flush(); fos.close(); } catch (IOException e) { e.printStackTrace(); } Log.d(TAG, screenShoot: ); } private Bitmap viewShot(LinearLayout linearLayout) { int h 0; Bitmap bitmap; for (int i 0; i linearLayout.getChildCount(); i) { h linearLayout.getChildAt(i).getHeight(); } bitmap Bitmap.createBitmap(linearLayout.getWidth(), h, Bitmap.Config.ARGB_8888); Canvas canvas new Canvas(bitmap); linearLayout.draw(canvas); return bitmap; }NULL图3.View截图效果图随便使用一个界面进行截图效果如图3所示截出来的图只显示组件背景是透明的有点像抠图效果。需要注意的是view截图只截传进去的应用的layout里面的组件不在layout里面的组件无法截出来也不会截取导航栏。5.截图参考文章参考文章Android 多种截屏方式介绍_android 截屏_Mr_Leixiansheng的博客-CSDN博客https://blog.csdn.net/Mr_Leixiansheng/article/details/103491099https://blog.csdn.net/Mr_Leixiansheng/article/details/103491099分屏小窗功能简介类似于下面这种播放视频退出视频播放页可以系统任意位置(除开一些特殊场景)进行小窗口播放视频。一般小窗口上具有播放暂停、上下曲、关闭、放大进入播放页、可拖动功能。图4. 视频小窗效果图方法一使用Android原生画中画这个是安卓原生提供的完成视频小窗功能的组件。介绍和demo地址如下图所示参考文章安卓PiP官方地址参考地址PiP官方demo地址优点1、方便使用。缺点1、点击小窗口的时候会闪一下不知道原因。2、需要底层支持现在framework.jar没有暴露pip相关接口自定义不了如果用这个需要framework那边加用这个就相当于把应用层的视频播放逻辑整到fw那边去了不方便应用层修改到时候出问题了都不好排查。3、有一些细细小小的bug看着不严重但影响体验又改不掉改不动。4、看了网上一圈和看demo很少有人用这个来实现画中画功能一堆人劝退。建议有其他方案选其他方案。参考文章Android画中画功能避坑指南方法二使用WindowManger绑定服 务实现系统级别的自定义悬浮小窗口使用方式1、添加悬浮窗功能权限uses-permission android:nameandroid.permission.SYSTEM_ALERT_WINDOW /2、使用WindowManger add一个viewpublic void showFloatingWindowView(Context context, String usbPath) { Log.d(TAG, showFloatingWindowView: ); mContext context; // 悬浮窗显示视图 mShowView initFloatView(); // 获取系统窗口管理服务 mWindowManager (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); // 悬浮窗口参数设置及返回 mFloatParams getParams(context); // 设置窗口触摸移动事件 mShowView.setOnTouchListener(new FloatViewMoveListener()); // 悬浮窗生成 mWindowManager.addView(mShowView, mFloatParams); init(usbPath); getUSBVideoControlTool.registerMediaStatusChangeListener(TAG, iMediaStatusChange); DeviceStatusBean.getInstance().addDeviceListener(deviceListener); initData(); }3、使用服务绑定这个弹窗让其成为系统弹窗可以在其他应用上面弹出public class FloatingWindowService extends Service { private static final String TAG FloatingWindowService; public static final String ACTION com.lwj.galleryapp.service; private VideoFloatingWindow mUSB0VideoFloatingWindow; private VideoFloatingWindow mUSB1VideoFloatingWindow; Nullable Override public IBinder onBind(Intent intent) { Log.d(TAG, onBind: ); return null; } Override public void onCreate() { super.onCreate(); Log.d(TAG, onCreate: ); ServiceUtils.startForegroundNotification(this, FloatingWindowService, FloatingWindowService); TempMemoryUtil.getInstance().registerVideoScreenTypeChangeListeners(iVideoScreenTypeChangeListener); } Override public void onDestroy() { super.onDestroy(); Log.d(TAG, onDestroy: ); TempMemoryUtil.getInstance().unRegisterVideoScreenTypeChangeListeners(iVideoScreenTypeChangeListener); } Override public int onStartCommand(Intent intent, int flags, int startId) { return super.onStartCommand(intent, flags, startId); } private void showUSB0FloatingWindow() { Log.d(TAG, showUSB0FloatingWindow: ); mUSB0VideoFloatingWindow new VideoFloatingWindow(); mUSB0VideoFloatingWindow.showFloatingWindowView(this, USBConstants.USBPath.USB0_PATH); } private void dismissUSB0FloatingWindow() { Log.d(TAG, dismissUSB0FloatingWindow: ); if (mUSB0VideoFloatingWindow ! null) { mUSB0VideoFloatingWindow.dismiss(); } } private void showUSB1FloatingWindow() { Log.d(TAG, showUSB1FloatingWindow: ); mUSB1VideoFloatingWindow new VideoFloatingWindow(); mUSB1VideoFloatingWindow.showFloatingWindowView(this, USBConstants.USBPath.USB1_PATH); } private void dismissUSB1FloatingWindow() { Log.d(TAG, dismissUSB1FloatingWindow: ); if (mUSB1VideoFloatingWindow ! null) { mUSB1VideoFloatingWindow.dismiss(); } } IVideoScreenTypeChangeListener iVideoScreenTypeChangeListener new IVideoScreenTypeChangeListener() { Override public void onUSB0CurrentVideoScreenType(int type) { if (type TempMemoryUtil.VIDEO_FULL_SCREEN) { dismissUSB0FloatingWindow(); } else if (type TempMemoryUtil.VIDEO_SPLIT_SCREEN) { showUSB0FloatingWindow(); } } Override public void onUSB1CurrentVideoScreenType(int type) { if (type TempMemoryUtil.VIDEO_FULL_SCREEN) { dismissUSB1FloatingWindow(); } else if (type TempMemoryUtil.VIDEO_SPLIT_SCREEN) { showUSB1FloatingWindow(); } } }; }4、退出视频播放界面使用分屏小窗时将view上的surface绑定到公共MediaPlayer上面使画面同步渲染到小窗口上。private void showUSB1FloatingWindow() { Log.d(TAG, showUSB1FloatingWindow: ); mUSB1VideoFloatingWindow new VideoFloatingWindow(); mUSB1VideoFloatingWindow.showFloatingWindowView(this, USBConstants.USBPath.USB1_PATH); }5、在view上处理各个按钮的功能逻辑View.OnClickListener mOnClickListener new View.OnClickListener() { SuppressLint(NonConstantResourceId) Override public void onClick(View v) { switch (v.getId()) { case R.id.iv_floating_window_close_btn: USBVideoControlTool.processCommand(MediaAction.STOP, ChangeReasonData.UI_FINISH); if (mCurrentUsb.equals(USBConstants.USBPath.USB0_PATH)) { TempMemoryUtil.getInstance().setUSB0CurrentVideoScreenType(TempMemoryUtil.VIDEO_FULL_SCREEN); } else if (mCurrentUsb.equals(USBConstants.USBPath.USB1_PATH)) { TempMemoryUtil.getInstance().setUSB1CurrentVideoScreenType(TempMemoryUtil.VIDEO_FULL_SCREEN); } break; case R.id.iv_floating_window_full_screen_btn: if (mCurrentUsb.equals(USBConstants.USBPath.USB0_PATH)) { initVideoPlayActivity(CurrentPlayInfo.getInstance(MediaType.USB1_VIDEO).getCurrentPlayItem().getPath()); } else if (mCurrentUsb.equals(USBConstants.USBPath.USB1_PATH)) { initVideoPlayActivity(CurrentPlayInfo.getInstance(MediaType.USB2_VIDEO).getCurrentPlayItem().getPath()); } dismiss(); break; case R.id.iv_floating_window_pre_btn: USBVideoControlTool.processCommand(MediaAction.PRE, ChangeReasonData.CLICK); break; case R.id.iv_floating_window_play_btn: USBVideoControlTool.processCommand(MediaAction.PLAY_OR_PAUSE, ChangeReasonData.CLICK); break; case R.id.iv_floating_window_next_btn: USBVideoControlTool.processCommand(MediaAction.NEXT, ChangeReasonData.CLICK); break; } } };6、更新界面消息按钮啥的可以使用WindowManager的updateViewLayout方式Override public void onPlayStatusChange(boolean isPlaying) { mIvPlayBtn.post(new Runnable() { Override public void run() { if (isPlaying) { mIvPlayBtn.setBackground(mContext.getDrawable(com.lwj.galleryresources.R.drawable.common_pause_icon)); } else { mIvPlayBtn.setBackground(mContext.getDrawable(com.lwj.galleryresources.R.drawable.common_playing_icon)); } mWindowManager.updateViewLayout(mViewFloatingWindow, mFloatParams); } }); }7、退出view返回播放界面时记得重新将播放界面的surface与公共MediaPlayer绑定一下。详细代码查看附件1.缺点1、小窗和播放界面不能同时在一个界面播放。为保持播放页面和小窗画面同步需要使用一个MediaPlayer我了解到一个MediaPlayer只能设置一个surface其他应用分屏小窗功能好像也没有小窗口和播放界面同时播放如果无特殊需求该缺点可以忽略。2、处理不好播放节目和小窗口的画面数据渲染容易出现黑屏、停止播放等问题。优点1、可行性非常好可以除了可以满足上述分屏小窗的功能对代码层面来说还可以自定义按钮弹窗样式弹出方式和位置就类似于给个悬浮窗口想怎么整怎么整。2、可控性非常好小窗口画面不同步黑屏切换回播放主界面出点什么问题都特别好排查bug很少自定义写得好基本可以没有bug。3、博客上一大推教程大家都推荐使用这种方式我试了一下b站貌似也是用的这种方式我把悬浮窗口的权限关闭了它就不能在其他应用进行分屏小窗功能了。个人推荐使用这种方法实现视频分屏小窗功能。方法三使用Presentation看网上有那种双屏异显的时候会用到但是不会用比较考验对屏幕和surface层级的研究。感兴趣的可以自己研究一下。U盘播放时长记忆简介需要实现一个记忆各个视频播放时长的功能kk以后我们应该都会使用安卓原生MediaStore功能来查询U盘数据这个时候可以使用MediaStore的video表中的bookmark字段。顾名思义这个标签的意思是书签用于记录视频播放时长。cursor.getInt(cursor.getColumnIndex(MediaStore.Video.Media.BOOKMARK))使用方式1、在视频播放界面退出去时修改MediaStore的这个标签通知数据改变。SuppressLint(NewApi) public void updateData(FileMessage fileMessage) { Log.d(TAG, updateData: fileMessage); MediaThreadPoolExecutorUtils.getInstance().submit(new Runnable() { Override public void run() { ContentValues contentValues new ContentValues(); contentValues.put(bookmark, fileMessage.getBookmark()); int update contentResolver.update(MediaStore.Video.Media.EXTERNAL_CONTENT_URI, contentValues, _data ?, new String[]{fileMessage.getPath()}); //通知数据变化 notifyUpdate(fileMessage); } }); }2、查询已播放时长。Override protected ListFileMessage query(Cursor cursor) { ListFileMessage videoList new ArrayList(); if (cursor ! null) { while (cursor.moveToNext()) { FileMessage fm new FileMessage(); fm.setId(cursor.getInt(cursor.getColumnIndex(MediaStore.Video.Media._ID))); fm.setPath(cursor.getString(cursor.getColumnIndex(MediaStore.Video.Media.DATA))); fm.setDuration(cursor.getInt(cursor.getColumnIndex(MediaStore.Video.Media.DURATION))); fm.setName(cursor.getString(cursor.getColumnIndex(MediaStore.Video.Media.TITLE))); fm.setFileName(cursor.getString(cursor.getColumnIndex(MediaStore.Video.Media.DISPLAY_NAME))); fm.setLastModified(cursor.getLong(cursor.getColumnIndex(MediaStore.Video.Media.DATE_MODIFIED))); fm.setSize(cursor.getLong(cursor.getColumnIndex(MediaStore.Video.Media.SIZE))); fm.setBookmark(cursor.getInt(cursor.getColumnIndex(MediaStore.Video.Media.BOOKMARK))); fm.setMediaType(FileMessage.VIDEO_TYPE); videoList.add(fm); } cursor.close(); } return videoList; }优点1、与媒体数据一起放在MediaStore的表中查询修改记忆方便拔插U盘也可以记忆全部视频数据的各个视频的播放时长。2、与现有的数据存储查询方案更加契合。缺点1、这个书签只在video和music这张表中使用查询的时候记得不要去查图片的数据库。

相关文章:

安卓demo-壁纸预览、分屏小窗与U盘播放时长记忆功能

壁纸预览 1.背景 有的项目需要做壁纸功能,就会用到壁纸预览功能。类似于手机上的壁纸预览功能: 选择图片->点击预览->桌面上的组件、应用图片名称等会出现在壁纸上。 图1.实际桌面与壁纸预览界面 2.现状分析 现在桌面已经做成一个应用了&…...

TensorFlow Recommenders多任务学习指南:同时优化多个推荐目标

TensorFlow Recommenders多任务学习指南:同时优化多个推荐目标 【免费下载链接】recommenders TensorFlow Recommenders is a library for building recommender system models using TensorFlow. 项目地址: https://gitcode.com/gh_mirrors/rec/recommenders …...

5个步骤扩展Cookiecutter项目模板功能:打造专属插件系统

5个步骤扩展Cookiecutter项目模板功能:打造专属插件系统 【免费下载链接】cookiecutter A cross-platform command-line utility that creates projects from cookiecutters (project templates), e.g. Python package projects, C projects. 项目地址: https://g…...

中兴光猫终极管理指南:zteOnu一键开启工厂模式与永久Telnet的完整教程

中兴光猫终极管理指南:zteOnu一键开启工厂模式与永久Telnet的完整教程 【免费下载链接】zteOnu A tool that can open ZTE onu device factory mode 项目地址: https://gitcode.com/gh_mirrors/zt/zteOnu 中兴光猫是许多家庭和企业网络的核心设备&#xff0c…...

Awesome Diffusion Models in Medical Imaging:医学影像扩散模型完全入门指南

Awesome Diffusion Models in Medical Imaging:医学影像扩散模型完全入门指南 【免费下载链接】Awesome-Diffusion-Models-in-Medical-Imaging Diffusion Models in Medical Imaging (Published in Medical Image Analysis Journal) 项目地址: https://gitcode.co…...

利川乡村民宿:口碑驱动的选品与运营策略解析

利川乡村民宿:口碑驱动的选品与运营策略解析“‘利川乡村民宿的核心竞争力,从来不是装修多豪华,而是能否让游客真正享受清凉与安心’——这是利川乡村民宿行业的共识,但如何选到靠谱的民宿、理解其运营逻辑,却困扰着不…...

数据智能代理DATAMIND架构与实战解析

1. 项目概述DATAMIND这个项目名称本身就透露着浓厚的"数据智能"气息。作为一个长期混迹数据科学圈的老兵,我第一眼看到这个标题就意识到,这绝不是一个简单的数据分析工具,而是一个具备自主学习和决策能力的智能代理系统。这类系统正…...

以水胜刚,SAP HANA 开发里的柔弱之道

老子说「天下莫柔弱於水。而攻坚强者,莫之能胜。」这一句放到 SAP HANA 开发里,我会把它理解成一种很朴素的工程直觉,系统里真正强大的东西,往往不是堆得最厚的过程代码,不是最长的 SQLScript,不是最复杂的 Calculation View,也不是到处加索引、到处建中间表、到处写强制…...

抖音下载器完整指南:5分钟学会批量下载无水印抖音视频

抖音下载器完整指南:5分钟学会批量下载无水印抖音视频 【免费下载链接】douyin-downloader A practical Douyin downloader for both single-item and profile batch downloads, with progress display, retries, SQLite deduplication, and browser fallback suppo…...

LLM上下文工程化实践:从向量检索到智能问答的完整解决方案

1. 项目概述:从“上下文”到“工程化”的桥梁 如果你是一名AI应用开发者,或者正在尝试将大语言模型(LLM)集成到你的产品中,那么“上下文管理”这个词对你来说一定不陌生,甚至可能是一个痛点。我们常常会遇到…...

算法题(173):枚举排列

审题: 本题需要我们找出所有排列方式并按照字典序排序输出 思路: 方法一:dfs深度优先搜索 由于最后还需要我们按照字典序输出,且无法事先确定需要的for循环层数,所以我们这里不能采用简单的for循环解决 决策树&#xf…...

浏览器沙箱环境构建:安全执行与结构化回显的实现原理

1. 项目概述:一个浏览器内的指令回显工具最近在折腾一些前端自动化测试和交互原型开发时,我常常遇到一个需求:需要快速验证浏览器环境下的指令执行结果,或者想直观地看到某个JavaScript API在特定上下文中的行为。手动打开控制台敲…...

算法题(172):组合型枚举

审题: 本题需要我们对1到n的数进行n中取m的组合枚举,找到所有不同的组合并按照字典序输出,要求行内和行间都满足字典序 思路: 本题我们采用枚举的方法,但是用for循环暴力枚举会有两个大问题 其一是无法确定for循环个数…...

从零到千档:AXOrderBook如何重塑A股市场深度洞察

从零到千档:AXOrderBook如何重塑A股市场深度洞察 【免费下载链接】AXOrderBook A股订单簿工具,使用逐笔行情进行订单簿重建、千档快照发布、各档委托队列展示等,包括python模型和FPGA HLS实现。 项目地址: https://gitcode.com/gh_mirrors/…...

树莓派4B与STM32串口通信保姆级教程:从GPIO引脚连接到minicom调试全流程

树莓派4B与STM32串口通信全流程实战指南 引言 嵌入式开发中,串口通信是最基础也最关键的技能之一。作为初学者,你可能已经听说过树莓派和STM32这两个名字——前者是当下最受欢迎的单板计算机,后者则是嵌入式领域广泛使用的微控制器。将它们通…...

AISMM白皮书深度拆解:5大核心模块、87个评估维度、23个典型误用陷阱——一线架构师手把手带你避坑

更多请点击: https://intelliparadigm.com 第一章:2026奇点智能技术大会:AISMM白皮书下载 2026奇点智能技术大会(Singularity Intelligence Summit 2026)正式发布《AI System Maturity Model(AISMM&#…...

暗黑破坏神2重制版自动化刷宝终极指南:Botty像素级智能助手全解析

暗黑破坏神2重制版自动化刷宝终极指南:Botty像素级智能助手全解析 【免费下载链接】botty D2R Pixel Bot 项目地址: https://gitcode.com/gh_mirrors/bo/botty 想要在《暗黑破坏神2重制版》中解放双手,实现高效自动刷宝吗?Botty作为一…...

Vue3+TypeScript在线演示文稿编辑器的技术实现深度解析

Vue3TypeScript在线演示文稿编辑器的技术实现深度解析 【免费下载链接】PPTist PowerPoint-ist(/pauəpɔintist/), An online presentation application that replicates most of the commonly used features of MS PowerPoint, allowing for the editi…...

艾体宝洞察|面向 Agentic AI 场景:基于原生多模型架构构建“统一上下文层”

随着大语言模型(LLM)能力的演进,AI 应用的开发正在从单轮问答式的 RAG(检索增强生成),向具备长程规划与工具调用能力的智能体(AI Agent)架构迁移。 然而,从工程实践的角度…...

Docker网络延迟高达400ms?用eBPF+量子调度模型实时诊断,3分钟定位瓶颈

更多请点击: https://intelliparadigm.com 第一章:Docker网络延迟的量子化认知革命 传统网络性能分析常将延迟视为连续可微的宏观量,而 Docker 容器间通信却在内核网络栈、cgroup 限流、iptables 规则与 veth pair 驱动层叠作用下&#xff0…...

如何快速安装和配置QLMarkdown:新手入门教程

如何快速安装和配置QLMarkdown:新手入门教程 【免费下载链接】QLMarkdown macOS Quick Look extension for Markdown files. 项目地址: https://gitcode.com/gh_mirrors/qlm/QLMarkdown QLMarkdown是一款专为macOS设计的Quick Look扩展工具,能帮助…...

终极Photoshop纹理压缩指南:Intel Texture Works插件完整使用教程

终极Photoshop纹理压缩指南:Intel Texture Works插件完整使用教程 【免费下载链接】Intel-Texture-Works-Plugin Intel has extended Photoshop* to take advantage of the latest image compression methods (BCn/DXT) via plugin. The purpose of this plugin is …...

Miku-LuaProfiler安全性与稳定性:如何避免Hook导致的崩溃问题

Miku-LuaProfiler安全性与稳定性:如何避免Hook导致的崩溃问题 【免费下载链接】Miku-LuaProfiler 项目地址: https://gitcode.com/gh_mirrors/mi/Miku-LuaProfiler Miku-LuaProfiler是一款功能强大的Lua性能分析工具,通过Hook技术实现对Lua代码执…...

ied生命周期脚本执行机制:从安装到构建的完整流程

ied生命周期脚本执行机制:从安装到构建的完整流程 【免费下载链接】ied :package: Like npm, but faster - an alternative package manager for Node 项目地址: https://gitcode.com/gh_mirrors/ie/ied ied作为一款快速的Node.js替代包管理器,其…...

三步搞定B站4K视频下载:开源工具让大会员内容永久保存

三步搞定B站4K视频下载:开源工具让大会员内容永久保存 【免费下载链接】bilibili-downloader B站视频下载,支持下载大会员清晰度4K,持续更新中 项目地址: https://gitcode.com/gh_mirrors/bil/bilibili-downloader 在数字内容消费日益…...

别再只查命令了!深入理解树莓派I2C通信,从驱动到应用层玩转DS3231 RTC模块

树莓派I2C通信深度解析:从DS3231驱动到Python寄存器级操作 树莓派作为嵌入式开发的明星平台,其I2C接口的灵活性和可扩展性一直备受开发者青睐。但大多数教程仅停留在基础命令操作层面,对于想真正掌握硬件交互本质的开发者来说,这远…...

如何快速创建Serverless项目:Cookiecutter模板的终极指南

如何快速创建Serverless项目:Cookiecutter模板的终极指南 【免费下载链接】cookiecutter A cross-platform command-line utility that creates projects from cookiecutters (project templates), e.g. Python package projects, C projects. 项目地址: https://…...

别再踩坑了!Windows下用Code::Blocks搭建LVGL模拟器(V9版)的完整避坑指南

Windows下用Code::Blocks搭建LVGL V9模拟器的完整避坑指南 最近在Windows平台上用Code::Blocks搭建LVGL V9模拟器时,发现网上大部分教程都是针对V8版本的,导致在文件系统访问环节频频踩坑。本文将分享我从环境准备到成功运行的全过程,特别是那…...

暗黑破坏神2存档编辑器:快速掌握免费角色与物品管理终极指南

暗黑破坏神2存档编辑器:快速掌握免费角色与物品管理终极指南 【免费下载链接】d2s-editor 项目地址: https://gitcode.com/gh_mirrors/d2/d2s-editor d2s-editor是一款功能强大的暗黑破坏神2游戏存档编辑工具,专为《暗黑破坏神2》经典版和重制版…...

Think3D框架:增强视觉语言模型的3D空间推理能力

1. 项目背景与核心价值最近在计算机视觉和自然语言处理的交叉领域,3D空间理解能力正成为新一代多模态模型的必备技能。Think3D框架的提出,恰好填补了当前视觉语言模型在三维场景理解方面的关键短板。传统视觉语言模型如CLIP、BLIP等在2D图像描述和问答任…...