具体流程大概是这样的:
1.需要加载某个类时,先检查自定义类加载器是否加载过,如果已经加载过,则直接返回。
2.如果自定义类加载器没有加载过,则检查应用程序类加载器是否加载过,如果已经加载过,则直接返回。
3.如果应用程序类加载器没有加载过,则检查扩展类加载器是否加载过,如果已经加载过,则直接返回。
4.如果扩展类加载器没有加载过,则检查启动类加载器是否加载过,如果已经加载过,则直接返回。
5.如果启动类加载器没有加载过,则判断当前类加载器能否加载这个类,如果能加载,则加载该类,然后返回。
6.如果启动类加载器不能加载该类,则交给扩展类加载器。扩展类加载器判断能否加载这个类,如果能加载,则加载该类,然后返回。
7.如果扩展类加载器不能加载该类,则交给应用程序类加载器。应用程序类加载器判断能否加载这个类,如果能加载,则加载该类,然后返回。
8.如果应用程序类加载器不能加载该类,则交给自定义类加载器。自定义类加载器判断能否加载这个类,如果能加载,则加载该类,然后返回。
9.如果自定义类加载器,也无法加载这个类,则直接抛ClassNotFoundException异常。
这样做的好处是:
1.保证类不会重复加载。加载类的过程中,会向上问一下是否加载过,如果已经加载了,则不会再加载,这样可以保证一个类只会被加载一次。
2.保证类的安全性。核心的类已经被启动类加载器加载了,后面即使有人篡改了该类,也不会再加载了,防止了一些有危害的代码的植入。
线程池执行流程:
1.线程池初始化的时候里面是没有线程的,工作队列是以参数的形式传进来的,而且就算工作队列里面有任务也不会马上去执行
2.当调用execute() 方法添加任务时会做如下判断
如果当前线程数小于核心线程数,则新建线程执行任务
如果当前线程数大于核心线程数,则将任务加入工作队列
如果工作队列满了,且当前线程数小于最大线程数,则新建线程执行任务
如果工作队列满了,且当前线程数大于最大线程数,则执行拒绝策略
3.当一个线程完成任务时,会从工作队列中取一个任务来执行
4.当一个线程空闲时,会先判断当前线程数大于是否大于核心线程数,如果当前线程数大于核心线程数,那么此线程会在存活一定时间(keepAliveTime)后销毁,最后线程池中的线程数会保持在corePoolSize的大小
通过AAPT工具进行资源文件(包括AndroidManifest.xml、布局文件、各种xml资源等)的打包,生成R.java文件。
通过AIDL工具处理AIDL文件,生成相应的Java文件。
通过Javac工具编译项目源码,生成Class文件。
通过DEX工具将所有的Class文件转换成DEX文件,该过程主要完成Java字节码转换成Dalvik字节码,压缩常量池以及清除冗余信息等工作。
通过ApkBuilder工具将资源文件、DEX文件打包生成APK文件。
利用KeyStore对生成的APK文件进行签名。
如果是正式版的APK,还会利用ZipAlign工具进行对齐处理,对齐的过程就是将APK文件中所有的资源文件举例文件的起始距离都偏移4字节的整数倍,这样通过内存映射访问APK文件 的速度会更快。