13.1 使用CrashHandler来获取应用的Crash信息

(1)应用发生Crash在所难免,但是如何采集crash信息以供后续开发处理这类问题呢?

利用Thread类的setDefaultUncaughtExceptionHandler方法!

defaultUncaughtHandler是Thread类的静态成员变量,所以如果我们将自定义的UncaughtExceptionHandler设置给Thread的话,那么当前进程内的所有线程都能使用这个UncaughtExceptionHandler来处理异常了。

public static void setDefaultUncaughtExceptionHandler(UncaughtExceptionHandler handler) {    Thread.defaultUncaughtHandler = handler;}

(2)作者实现了一个简易版本的UncaughtExceptionHandler类的子类CrashHandler,源码传送门

CrashHandler的使用方式就是在Application的onCreate方法中设置一下即可

//在这里为应用设置异常处理程序,然后我们的程序才能捕获未处理的异常CrashHandler crashHandler = CrashHandler.getInstance();crashHandler.init(this);

13.2 使用multidex来解决方法数越界

(1)在Android中单个dex文件所能够包含的最大方法数是65536,这包含Android Framework、依赖的jar以及应用本身的代码中的所有方法。如果方法数超过了最大值,那么编译会报错DexIndexOverflowException。

有时方法数没有超过最大值,但是安装在低版本手机上时应用异常终止了,报错Optimization failed。这是因为应用在安装的时候,系统会通过dexopt程序来优化dex文件,在优化的过程中dexopt采用一个固定大小的缓冲区来存储应用中所有方法的信息,这个缓冲区就是LinearAlloc。LinearAlloc缓冲区在新版本的Android系统中大小是8MB或者16MB,但是在Android 2.2和2.3中却只有5MB,当待安装的应用的方法数比较多的时候,尽管它还没有达到最大方法数,但是它的存储空间仍然有可能超过5MB,这种情况下dexopt就会报错导致安装失败。

(2)如何解决方法数越界的问题呢?

Google在2014年提出了简单方便的multidex的解决方案。
在Android 5.0之前使用multidex需要引入android-support-multidex.jar包,从Android 5.0开始,系统默认支持了multidex,它可以从apk中加载多个dex。Multidex方案主要针对AndroidStudio和Gradle编译环境。
使用Multidex的步骤:
1.在build.gradle文件中添加multiDexEnabled true

android {    ...    defaultConfig {        ...        multiDexEnabled true // [添加的配置] enable multidex support    }    ...}

2.添加对multidex的依赖

compile 'com.android.support:multidex:1.0.0'

3.在代码中添加对multidex的支持,这里有三种方案:

① 在AndroidManifest文件中指定Application为MultiDexApplication

<application android:name="android.support.multidex.MultiDexApplication"...</application>

② 让应用的Application继承自MultiDexApplication

③ 重写Application的attachBaseContext方法,这个方法要先于onCreate方法执行

public class TestApplication extends Application {    @Override    protected void attachBaseContext(Context base) {        super.attachBaseContext(base);        MultiDex.install(this); //    }}

采用上面的配置之后,如果应用的方法数没有越界,那么Gradle并不会生成多个dex文件;如果方法数越界后,Gradle就会在apk中打包2个或者多个dex文件,具体会打包多少个dex文件要看当前项目的代码规模。在有些情况下,可能需要指定主dex文件中所要包含的类,这个可以通过–main-dex-list选项来实现这个功能。

afterEvaluate {    println "afterEvaluate"    tasks.matching {        it.name.startsWith('dex')    }.each { dx ->        def listFile = project.rootDir.absolutePath + '/app/maindexlist.txt'        println "root dir:" + project.rootDir.absolutePath        println "dex task found: " + dx.name        if (dx.additionalParameters == null) {            dx.additionalParameters = []        }        dx.additionalParameters += '--multi-dex'        dx.additionalParameters += '--main-dex-list=' + listFile        dx.additionalParameters += '--minimal-main-dex'    }}

–multi-dex表明当方法数越界时生成多个dex文件,–main-dex-list指定了要在主dex中打包的类的列表,–minimal-main-dex表明只有–main-dex-list所指定的类才能打包到主dex中。multidex的jar包中的9个类必须要打包到主dex中,其次不能在Application中成员以及代码块中访问其他dex中的类,否个程序会因为无法加载对应的类而中止执行。

(3)Multidex方案可能带来的问题:

1.应用启动速度会降低,因为应用启动的时候会加载额外的dex文件,所以要避免生成较大的dex文件;
2.需要做大量的兼容性测试,因为Dalvik LinearAlloc的bug,可能导致使用multidex的应用无法在Android 4.0以前的手机上运行。

13.3 Android的动态加载技术

(1)动态加载技术又称插件化技术,将应用插件化可以减轻应用的内存和CPU占用,还可以在不发布新版本的情况下更新某些模块。不同的插件化方案各有特色,但是都需要解决三个基础性问题:资源访问,Activity生命周期管理和插件ClassLoader的管理。

(2)宿主和插件:宿主是指普通的apk,插件是经过处理的dex或者apk。在主流的插件化框架中多采用特殊处理的apk作为插件,处理方式往往和编译以及打包环节有关,另外很多插件化框架都需要用到代理Activity的概念,插件Activity的启动大多数是借助一个代理Activity来实现的。

(3)资源访问:宿主程序调起未安装的插件apk,插件中凡是R开头的资源都不能访问了,因为宿主程序中并没有插件的资源,通过R来访问插件的资源是行不通的。
Activity的资源访问是通过ContextImpl来完成的,它有两个方法getAssets()和getResources()方法是用来加载资源的。
具体实现方式是通过反射,调用AssetManager的addAssetPath方法添加插件的路径,然后将插件apk中的资源加载到Resources对象中即可。

(4)Activity生命周期管理:有两种常见的方式,反射方式和接口方式。反射方式就是通过反射去获取Activity的各个生命周期方法,然后在代理Activity中去调用插件Activity对应的生命周期方法即可。
反射方式代码繁琐,性能开销大。接口方式将Activity的生命周期方法提取出来作为一个接口,然后通过代理Activity去调用插件Activity的生命周期方法,这样就完成了插件Activity的生命周期管理。

(5)插件ClassLoader的管理:为了更好地对多插件进行支持,需要合理地去管理各个插件的DexClassLoader,这样同一个插件就可以采用同一个ClassLoader去加载类,从而避免了多个ClassLoader加载同一个类时所引起的类型转换错误。

其他详细信息看作者插件化框架singwhatiwanna/dynamic-load-apk

13.4 反编译初步

1.主要介绍使用dex2jar和jd-gui反编译apk和使用apktool对apk进行二次打包,比较简单,略过不总结。

更多相关文章

  1. Android(安卓)Jetpack(二)ViewModel 组件原理剖析
  2. android scrollview 滑动到顶端或者指定位置
  3. eclipse ADT插件安装碰到的错误
  4. Android(安卓)完全退出当前应用程序
  5. Android学习之旅(三)----Activity及其生命周期
  6. 【android】消息传递利器EventBus的使用
  7. WindowManager和WindowManager.LayoutParams的使用以及实现悬浮
  8. Android(安卓)顶部灰条标题栏不显示的方法
  9. 彻底解决andorid h5交互!浅谈h5交互和js注入漏洞分析

随机推荐

  1. 浅析Android事件分发机制
  2. ubuntu10.04上android环境安装“org.ecli
  3. Android的休眠与唤醒
  4. This tag and its children can be repla
  5. Android(安卓)打开系统设置
  6. Android(安卓)全局异常错误或崩溃捕捉
  7. Android(安卓)Weekly Notes Issue #232
  8. [android] 将时长数为毫秒的转化为分钟和
  9. Android(安卓)cocos2d-x开发(二)之create-a
  10. [Android(安卓)Pro] 使用CursorLoader异