我的编程空间,编程开发者的网络收藏夹
学习永远不晚

Android动态加载资源实例解析

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

Android动态加载资源实例解析

  前不久跑去折腾高德 SDK 中的 HUD 功能,相信用过该功能的用户都知道 HUD 界面上的导航转向图标是动态变化的。从高德官方导航 javascript:;" onClick="javascript:tagshow(event, 'API');" target="_self">API 文档中 AMapNaviGuide 类的描述可知,导航转向图标有23种类型。   诶,等等,23 种?那图标应该是放在 assets 文件夹吧?总不可能是在服务器上下载吧?   看下导航 API 的 jar 包结构。   AMap_ Navi_v1.3.0_20150828.jar   |- assets   |- autonavi_Resource1_1_0.png   |- custtexture*.png (7 张)   |- com   |- amap.api.navi   |- autonavi   |- META-INF   纳尼?assets 上的图片总共也只有 8 张,而且图片的内容跟 HUD 毫无关系,莫非真的是从服务器下载资源?   用 Android Studio 打开 jar 包中的 AMapHudView.class 来看下 AMapHudView 的逻辑(AS 1.2 引入了反编译功能)。   ...   import com.autonavi.tbt.g;   ...   public class AMapHudView extends FrameLayout implements OnClickListener, OnTouchListener, e {   static final int[] hud_imgActions = new int[]{2130837532, 2130837532, 2130837532, 2130837533, 2130837534, 2130837535, 2130837536, 2130837537, 2130837538, 2130837539, 2130837522, 2130837523, 2130837524, 2130837525, 2130837526, 2130837527, 2130837528, 2130837529, 2130837530, 2130837531};   ...   private ImageView roadsignimg;// 方向图标对应的 View   ...   private int resId;// 方向图标的 id,对应 hud_imgActions 的 index,根据高德的文档,该变量值为 0-23   ...   private void updateHudWidgetContent() {   ...   if(this.roadsignimg != null && this.resId != 0 && this.resId != 1) {   Drawable var1 = g.a().getDrawable(hud_imgActions[this.resId]);// g.a() 返回的是 Resource 对象   this.roadsignimg.setBackgroundDrawable(var1);   ...   }   }   }   先看hud_imgActions,里面的值是不是很熟悉?转成16进制均为 0x7F02 开头(0x7F 是应用资源,而 0×02 则是 drawable 资源)。再看updateHudWidgetContent()方法,逻辑比较简单,通过resId获取hud_imgActions对应的 drawable id,再通过该 id 获取到对应的 Drawable 对象并将其设置到 ImageView 中。   看到这,可以肯定高德 SDK 终是通过本地资源的索引获取到 Drawable。   然而我们的 apk 中并没有相应的资源,为什么能够正常获取到对应的 Drawable?我们看回上面的第12行代码:   Drawable var1 = g.a().getDrawable(hud_imgActions[this.resId]);// g.a() 返回的是 Resource 对象   我们将注意力集中到g.a()中,找到com.autonavi.tbt.g#a()   public static Resources a() {   if (b == null) {   b = e.getResources();   }   return b;   }   其中变量e为上层传递进来的 Activity,而我们前面说过,我们的 apk 中并没有相应的资源,所以将注意力放到变量b在其他地方的赋值上。   public static boolean a(Context context) {   ...   a = b(context.getFilesDir() + "/autonavi_Resource1_1_0.jar");   b = a(context, a);// 变量 a 为 AssetManager   return true;   }   private static AssetManager b(String str) {   try {   Class cls = Class.forName("android.content.res.AssetManager");   AssetManager assetManager = (AssetManager) cls.getConstructor().newInstance();   try {   cls.getDeclaredMethod("addAssetPath", String.class).invoke(assetManager, str);   } catch (Throwable th) {   }   return assetManager;   } catch (Throwable th2) {   return null;   }   }   private static Resources a(Context context, AssetManager assetManager) {   DisplayMetrics displayMetrics = new DisplayMetrics();   displayMetrics.setToDefaults();   return new Resources(assetManager, displayMetrics, context.getResources().getConfiguration());   }   可以看到,高德 SDK 中先通过反射实例化 AssetManager,并且调用 `addAssetPath(context.getFilesDir() + “/autonavi_Resource1_1_0.jar”),接着实例化 Resources 对象。所以事实上是通过这个新的 Resource 来获取到对应资源的 Drawable 对象。   但是我们的 apk 对应的 files 目录中并不存在 autonavi_Resource1_1_0.jar,这个文件又是怎么来的?   private static String k = "autonavi_Resource1_1_0.png";   ...   private static boolean b(Context var0) {   String filePath = var0.getFilesDir().getAbsolutePath() + "/autonavi_Resource1_1_0.jar";   ...   InputStream var1 = var0.getResources().getAssets().open(k);   File var3 = new File(filePath);   long var21 = var3.length();   int var6 = var1.available();   if(!var3.exists() || var21 != (long)var6) {   ...   File var22 = new File(filePath);   FileOutputStream var2 = new FileOutputStream(var22);   byte[] var8 = new byte[1024];   int var9;   while((var9 = var1.read(var8)) > 0) {   var2.write(var8, 0, var9);   }   }   ...   }   还是 com.autonavi.tbt.g 这个类,可以看到,高德是将 jar 包内 assets 目录中的 autonavi_Resource1_1_0.png 复制到当前 apk 对应的 files 目录中,并将新的文件命名为 autonavi_Resource1_1_0.jar。   再回到加载资源的问题上,为什么加载 autonavi_Resource1_1_0.jar 能索引资源?   因为该文件其实是 apk(高德将后缀名改成了 jar)。AssetManager 加载该 apk 后,Resource 能通过该 AssetManager 获取到里面的相应资源。   AssetManager 的相关知识请参考老罗的《Android应用程序资源管理器(Asset Manager)的创建过程分析》   至此,我们可以清楚知道高德 SDK 是如何实现动态加载资源的:   将资源 apk 放置在 jar 包的 assets 目录中;   在 View 组件初始化的过程中将 assets 中的资源 apk 复制到 files 目录中;   接着实例化 AssetManager,调用 addAssetPath 方法加载 files 目录中的资源 apk;   然后将 AssetManager 作为参数实例化 Resouce,后通过 Resource 对象获取资源apk 中相应的资源。   总结   将上述内容再简略,动态加载资源所必需的几个核心步骤:   实例化 AssetManager 对象,并通过反射调用 addAssetPath(String) 方法加载目标 apk(或与 apk 文件架构一致的目录)   通过第一步得到的 AssetManager 实例化 Resource 对象   利用第二步得到的 Resource 对象来动态加载资源   这里需要注意的是,目标 apk(目录)需要放在context.getFilesDir()中,不然会加载失败(addAssetPath 返回 0)。另外,目标 apk 可以不签名,因为 addAssetPath 过程并没有进行签名校验。   获取资源 id   实际情况中,如果我们需要获取相应的资源,必须先获得资源对应的 id,而外部 apk 的 R.java 并不属于主 apk,这导致了获取资源的困难。   目前存在的解决方案有:   通过反射对应的 R 类获取对应的 id(极力不推荐,需要知道 field 的 name,若资源 apk 需要混淆,field name 更不知道是什么了,再者反射的效率并不理想)   通过接口获取对应的 id(优点在于灵活性高,主 apk 不需要关心资源。缺点在于若需要的资源较多,处理也较多。更多出现在获取固定资源的场景中,譬如应用换肤)   直接将资源 apk 的 R.java 放在主 apk 中,通过 R 获取 id(简单粗暴,但若资源 apk 中存在对应的 R.java,会发生冲突。混淆过则不存在这个问题。该方案缺乏灵活性,需要开发人员知道需要的资源名,对应的属性等。)   后两种方案各有各的优缺点,至于怎么选择,还得结合自身的场景。   应用场景   动态加载资源技术目前的一些应用场景主要有:   替换应用皮肤(如:QQ 空间)   减小主 apk 的大小,非重要资源放在服务端   类似于文中高德 SDK 的做法,使得 jar 包可以加载资源(这种应用可能现在比较少,以前这种做法也只是因为还没 aar)   后续   动态加载资源技术相关文章有很多,但我目前所看到的文章只涉及如何获取 drawable、string 等资源,并没有发现关于动态加载资源 apk 中的布局文件(我姿势不对?_(:з?∠)_)。后续会分享如何动态加载资源 apk 中的布局文件。


免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

Android动态加载资源实例解析

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

Android动态加载资源实例解析

前不久跑去折腾高德 SDK 中的 HUD 功能,相信用过该功能的用户都知道 HUD 界面上的导航转向图标是动态变化的。从高德官方导航 javascript:;" onClick="javascript:tagshow(event, 'API
2022-06-06

Android插件化之资源动态加载

Android插件化之资源动态加载一.概述Android插件化的一个重要问题就是插件资源访问问题,先列出会面对的问题1.如何加载插件资源 2.如何处理插件资源与宿主资源的处突:插件化资源问题要做到的效果是,如果我们要获取的资源在插件中找得到
2022-06-06

Android编程动态加载布局实例详解【附demo源码】

本文实例讲述了Android编程动态加载布局的方法。分享给大家供大家参考,具体如下: 由于前段时间项目需要,需要在一个页面上加载根据不同的按钮加载不同的布局页面,当时想到用 tabhot 。不过美工提供的界面图完全用不上tabhot ,所以
2022-06-06

Android 资源加载使用伪代码示例分析

这篇文章主要为大家介绍了Android 资源加载使用伪代码示例分析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
2022-11-13

JavaScript前端静态资源预加载实现示例

这篇文章主要为大家介绍了JavaScript前端静态资源预加载实现示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
2022-11-13

Android 加载assets中的资源文件实例代码

Android 加载assets资源 在android中,如何加载assets目录下的文件夹呢?方法很简单,使用 AssetManager, 即AssetManager assetManager = getAssets(); 例子如下:
2022-06-06

0xA03 Android 10 源码分析:APK 加载流程之资源加载

引言 这是 Android 10 源码分析系列的第 3 篇 分支:android-10.0.0_r14 全文阅读大概 15 分钟 首发于掘金:https://juejin.im/post/5e6c8c14f265da57… 通过这篇文章你将
2022-06-06

Android应用开发中Fragment的静态加载与动态加载实例

1、Fragment的静态使用 Fragment是作为Activity的UI的一部分,它内嵌在Activity中,多个Fragment可以把一个Activity分成多个部分,这在大屏幕手机或者平板电脑中会比较多的用到,这样就不用使用多个Ac
2022-06-06

使用SpringBoot如何实现加载静态资源

这篇文章给大家介绍使用SpringBoot如何实现加载静态资源,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。在SpringBoot中加载静态资源和在普通的web应用中不太一样。默认情况下,spring Boot从cla
2023-05-31

android动态加载布局文件示例

一、布局文件part.xml:代码如下:2022-06-06

vue3如何加载本地图片等静态资源浅析

在最近新起的项目中,用到了较新的技术栈vue3.2+vite+ts,跟着网上的写法渐渐上手了,下面这篇文章主要给大家介绍了关于vue3如何加载本地图片等静态资源的相关资料,需要的朋友可以参考下
2023-05-15

Android动态加载Activity原理详解

activity的启动流程 加载一个Activity肯定不会像加载一般的类那样,因为activity作为系统的组件有自己的生命周期,有系统的很多回调控制,所以自定义一个DexClassLoader类加载器来加载插件中的Activity肯定是
2022-06-06

网页资源阻塞浏览器加载的原理示例解析

这篇文章主要为大家介绍了网页资源阻塞浏览器加载的原理示例解析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
2023-03-07

编程热搜

  • Android:VolumeShaper
    VolumeShaper(支持版本改一下,minsdkversion:26,android8.0(api26)进一步学习对声音的编辑,可以让音频的声音有变化的播放 VolumeShaper.Configuration的三个参数 durati
    Android:VolumeShaper
  • Android崩溃异常捕获方法
    开发中最让人头疼的是应用突然爆炸,然后跳回到桌面。而且我们常常不知道这种状况会何时出现,在应用调试阶段还好,还可以通过调试工具的日志查看错误出现在哪里。但平时使用的时候给你闹崩溃,那你就欲哭无泪了。 那么今天主要讲一下如何去捕捉系统出现的U
    Android崩溃异常捕获方法
  • android开发教程之获取power_profile.xml文件的方法(android运行时能耗值)
    系统的设置–>电池–>使用情况中,统计的能耗的使用情况也是以power_profile.xml的value作为基础参数的1、我的手机中power_profile.xml的内容: HTC t328w代码如下:
    android开发教程之获取power_profile.xml文件的方法(android运行时能耗值)
  • Android SQLite数据库基本操作方法
    程序的最主要的功能在于对数据进行操作,通过对数据进行操作来实现某个功能。而数据库就是很重要的一个方面的,Android中内置了小巧轻便,功能却很强的一个数据库–SQLite数据库。那么就来看一下在Android程序中怎么去操作SQLite数
    Android SQLite数据库基本操作方法
  • ubuntu21.04怎么创建桌面快捷图标?ubuntu软件放到桌面的技巧
    工作的时候为了方便直接打开编辑文件,一些常用的软件或者文件我们会放在桌面,但是在ubuntu20.04下直接直接拖拽文件到桌面根本没有效果,在进入桌面后发现软件列表中的软件只能收藏到面板,无法复制到桌面使用,不知道为什么会这样,似乎并不是很
    ubuntu21.04怎么创建桌面快捷图标?ubuntu软件放到桌面的技巧
  • android获取当前手机号示例程序
    代码如下: public String getLocalNumber() { TelephonyManager tManager =
    android获取当前手机号示例程序
  • Android音视频开发(三)TextureView
    简介 TextureView与SurfaceView类似,可用于显示视频或OpenGL场景。 与SurfaceView的区别 SurfaceView不能使用变换和缩放等操作,不能叠加(Overlay)两个SurfaceView。 Textu
    Android音视频开发(三)TextureView
  • android获取屏幕高度和宽度的实现方法
    本文实例讲述了android获取屏幕高度和宽度的实现方法。分享给大家供大家参考。具体分析如下: 我们需要获取Android手机或Pad的屏幕的物理尺寸,以便于界面的设计或是其他功能的实现。下面就介绍讲一讲如何获取屏幕的物理尺寸 下面的代码即
    android获取屏幕高度和宽度的实现方法
  • Android自定义popupwindow实例代码
    先来看看效果图:一、布局
  • Android第一次实验
    一、实验原理 1.1实验目标 编程实现用户名与密码的存储与调用。 1.2实验要求 设计用户登录界面、登录成功界面、用户注册界面,用户注册时,将其用户名、密码保存到SharedPreference中,登录时输入用户名、密码,读取SharedP
    Android第一次实验

目录