在Android开发中如果存在多进程共享资源用法时, 会出现资源到不到问题.

真实碰到的问题, 记录下来提供同学们参考

一, 崩溃信息

崩溃日志如下

--------- beginning of crash
08-17 18:54:00.622 17167 17167 E AndroidRuntime: FATAL EXCEPTION: main
08-17 18:54:00.622 17167 17167 E AndroidRuntime: Process: com.mobile.emm.trustspace:gallery, PID: 17167
08-17 18:54:00.622 17167 17167 E AndroidRuntime: java.lang.RuntimeException: Unable to start activity ComponentInfo

{com.hulk.emm.trustspace/com.hulk.emm.camera1.GallerySettings}

: android.content.res.Resources$NotFoundException: Resource ID #0x7f0801b4
08-17 18:54:00.622 17167 17167 E AndroidRuntime: at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3782)
 ....................
//原因如下
08-17 18:54:00.622 17167 17167 E AndroidRuntime: Caused by: android.content.res.Resources$NotFoundException: Resource ID #0x7f0801b4
08-17 18:54:00.622 17167 17167 E AndroidRuntime: at android.content.res.ResourcesImpl.getValueForDensity(ResourcesImpl.java:311)
08-17 18:54:00.622 17167 17167 E AndroidRuntime: at android.content.res.Resources.getDrawableForDensity(Resources.java:993)
08-17 18:54:00.622 17167 17167 E AndroidRuntime: at android.content.res.Resources.getDrawable(Resources.java:933)
08-17 18:54:00.622 17167 17167 E AndroidRuntime: at android.content.Context.getDrawable(Context.java:687)
08-17 18:54:00.622 17167 17167 E AndroidRuntime: at com.android.internal.widget.ActionBarView.setIcon(ActionBarView.java:687)
08-17 18:54:00.622 17167 17167 E AndroidRuntime: at com.android.internal.widget.ActionBarOverlayLayout.setIcon(ActionBarOverlayLayout.java:921)
08-17 18:54:00.622 17167 17167 E AndroidRuntime: at com.android.internal.policy.PhoneWindow.setDefaultIcon(PhoneWindow.java:1860)
08-17 18:54:00.622 17167 17167 E AndroidRuntime: at android.app.Activity.initWindowDecorActionBar(Activity.java:3445)
08-17 18:54:00.622 17167 17167 E AndroidRuntime: at android.app.Activity.setContentView(Activity.java:3460)
08-17 18:54:00.622 17167 17167 E AndroidRuntime: at android.preference.PreferenceActivity.onCreate(PreferenceActivity.java:564)
08-17 18:54:00.622 17167 17167 E AndroidRuntime: at com.hulk.emm.camera1.GallerySettings.onCreate(GallerySettings.java:32)   //自定义的设置界面

二  原因分析

本崩溃场景: 主进程模块launcher,使用apk动态加载的方式运行gallery.apk

以debug版本apk分析(release版本的ID会有变化)

前提: gallery.apk的resources.arsc中资源drawable为: 0x7f080001-0x7f0801b3. 其中没有ic_launcher_appicon图片.

launcher模块manifest中声明 相册设置主题(android:theme="@android:style/Theme.Holo.Light")会加载天机的应用图标ic_launcher_appicon:
                                    android:excludeFromRecents="true"
                        android:process=":gallery"
                        android:screenOrientation="portrait"
                        android:theme="@android:style/Theme.Holo.Light"
                        android:permission="com.hulk.emm.permission.openAppActivity"
                        android:label="@string/preferences_label">
             

launcher中的ic_launcher_appicon的ID为0x7f0801a3

因业务需要,launcher引入增加mtess.aar(含有完整资源)
launcher模块中增加mtess.aar之后, 无形中加入了aar中的图片资源, launcher编译后的资源ID会增加, 其中drawable中ic_launcher_appicon的ID平移为0x7f0801b4, 超出了gallery.apk中ID最大值范畴(
0x7f0801b3),  相册gallery.apk运行时无法找到ID为0x7f0801b4的图片, 于是直接崩溃. (按照0x7f0801b4在gallery中查找图片,即使能找到图片,也不是ic_launcher_appicon图片).

注: 未增加mtess.aar前也有问题,只是没有触发, gallery中的图片ID最大值0x7f0801b3, ic_launcher_appicon的ID为0x7f0801a3, 相册运行时, 通过该ID加载的logo不是ic_launcher_appicon, 而是gallery中的其他图片.

三  解决问题两种方案
思路: 既然无法跨进程获取资源, 就两个方向: 一是去掉 跨进程直接调用资源用法,另辟蹊径, 二是 调用子模块中存在的目标资源.

具体如下:

1. 修改GallerySettings的主题为android:theme="@android:style/Theme.NoTitleBar", 自定义actionBar为(不适用默认的logo图标,自己实现ActionBar和点击事件)
                            android:id="@+id/toolbar"
                  android:layout_width="match_parent"
                  android:layout_height="wrap_content"
                  android:background="?attr/colorPrimary" />

2. 想办法在gallery中增加icon, manifest中的声明使用gallery中id数值较小的图片,只要保证侧图片在Byod-gallery.apk中存在即可,表示占位,没有实际显示出来(此方法不推荐)

以debug版本apk分析(release版本精简资源后,ID会有变化)
增加MTESS aar之后主进程drawable中ic_launcher_appicon的ID为0x7f0801b4 (标准版develop: 0x7f0801a3), mtess中的图片把ic_launcher_appicon的IDm往后平移,超出了gallery.apk中ID范畴, 安全相册gallery.apk运行进程中,无法找到ID为0x7f0801b4的图片.

以上问题为图片资源引发问题,实际开发中还可能会有其他资源问题, 如 styles/styles/string......

四. 总结 

1.    Android app编译apk时已经确定了资源ID,在resources.arsc文件中, AS编辑器打开可以看到 drawable/layout/styles/strings....资源对应的ID编号,与资源名称一一对应:

      android apk的资源ID编号在编译时就已经确定, 自定义的ID段位: 0x7f01XXXX-0x7fffXXXX,, 按照首字母排序的定义的, drawable为0x7f080000-0x7f08ffff, 通常最后一个为xml(0x7f13XXXX). 其他的段位是系统资源, eg: android:theme="@android:style/Theme.NoTitleBar" 编译出来的ID为: 0x0103006e;

具体的resources.arsc文件分析太复杂,此处不在深究, 可参考 https://www.jianshu.com/p/1347c782582d

2. 多进程运行时,每个进程只能拿到本进程的资源,不能直接获取其他进程资源共享(是指resources.arsc中定义的资源)

  (1)  apk动态加载的方式: apk独立子进程运行时所有资源都是子apk里面的resources.arsc中声明的ID和对应的资源, 不能使用主进程的资源.

  (2)  service运行在子进程,点用了主进程的资源ID.

  (3)  其他多进程多进程共享资源的场景.

   以上场景中如果没有特使处理,就处出现上面类似的崩溃信息.

3. 在manifest中声明时, 子进程的activity或者service等使用了主进程的资源, 编译的使用主进程的资源ID, 正常, 但是, 子进程实际运行时,根据资源类型, 按照ID查找,存在两个可能问题:
(1) 如果目标资源ID大于子进程apk中资源ID最大值, 找不到资源,直接崩溃; 
(2) 如果目标资源ID小于等于子进程apk中资源ID最大值, 实际拿到的theme/drawable/string等资源不是主进程中目标资源, 而是子进程其他图片;

更多相关文章

  1. Android(安卓)保存图片到相册无法显示的问题
  2. android资源类型
  3. gdb 远程调试android进程
  4. Android(安卓)不支持 SYSV IPC (SYSV IPC)
  5. Android(安卓)开发调试工具的使用总结
  6. android的tabHost的使用
  7. Android培训班(46)
  8. Android(安卓)ImageView图片自适应
  9. android button 基本原理

随机推荐

  1. const用法是什么?
  2. C语言中输出字符串用什么符号
  3. c语言输入五个数如何求平均值?
  4. c语言根号函数是什么
  5. c语言大于等于怎么打?
  6. c程序中宏展开是在什么时候进行的?
  7. 用C语言指针如何求最大值最小值
  8. c++定义数组的方法
  9. c语言中%是什么意思
  10. C语言程序的模块化通过什么实现