技术标签: android 知识点
classloader是所有classloader的父类(继承关系)
bootclssloader是所有classloader的parent(委托关系)
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.v("wanbai", "Activity的类加载加载器:" + Activity.class.getClassLoader() + ">>>code == " + Activity.class.getClassLoader().hashCode() );
Log.v("wanbai", "Context的类加载加载器:" + Context.class.getClassLoader() + ">>>code == " + Context.class.getClassLoader().hashCode());
Log.v("wanbai", "ListView的类加载器:" + ListView.class.getClassLoader() + ">>>code == " + ListView.class.getClassLoader().hashCode());
Log.v("wanbai", "------------------------------------------------------------------------------------------------------------------\n");
Log.v("wanbai", "MainActivity的类加载加载器:" + MainActivity.class.getClassLoader() + ">>>code == " + MainActivity.class.getClassLoader().hashCode() );
Log.v("wanbai", "应用程序默认加载器1:" + getClassLoader() + ">>>code == " + getClassLoader().hashCode());
Log.v("wanbai", "应用程序默认加载器2:" + this.getClass().getClassLoader() + ">>>code == " + this.getClass().getClassLoader().hashCode());
Log.v("wanbai", "应用程序默认加载器3:" + MainActivity.this.getClass().getClassLoader() + ">>>code == " + MainActivity.this.getClass().getClassLoader().hashCode());
Log.v("wanbai", "系统类加载器:" + ClassLoader.getSystemClassLoader() + ">>>code == " + ClassLoader.getSystemClassLoader().hashCode());
Log.v("wanbai", "------------------------------------------------------------------------------------------------------------------\n");
Log.v("wanbai", "打印应用程序默认加载器的委派机制:");
ClassLoader classLoader = getClassLoader();
while (classLoader != null) {
Log.v("wanbai", "类加载器:" + classLoader);
classLoader = classLoader.getParent();
}
Log.v("wanbai", "------------------------------------------------------------------------------------------------------------------\n");
Log.v("wanbai", "打印系统加载器的委派机制:");
classLoader = ClassLoader.getSystemClassLoader();
while (classLoader != null) {
Log.v("wanbai", "类加载器:" + classLoader);
classLoader = classLoader.getParent();
}
}
}
打印如下:
Activity的类加载加载器:java.lang.BootClassLoader@c692ed4>>>code == 208219860
Context的类加载加载器:java.lang.BootClassLoader@c692ed4>>>code == 208219860
ListView的类加载器:java.lang.BootClassLoader@c692ed4>>>code == 208219860
------------------------------------------------------------------------------------------------------------------
MainActivity的类加载加载器:dalvik.system.PathClassLoader[DexPathList[[zip file "/data/app/com.example.ndklearn-o6jgffmE45caOq26eG0gWg==/base.apk"],nativeLibraryDirectories=[/data/app/com.example.ndklearn-o6jgffmE45caOq26eG0gWg==/lib/arm64, /system/lib64, /system/vendor/lib64]]]>>>code == 17152125
应用程序默认加载器1:dalvik.system.PathClassLoader[DexPathList[[zip file "/data/app/com.example.ndklearn-o6jgffmE45caOq26eG0gWg==/base.apk"],nativeLibraryDirectories=[/data/app/com.example.ndklearn-o6jgffmE45caOq26eG0gWg==/lib/arm64, /system/lib64, /system/vendor/lib64]]]>>>code == 17152125
应用程序默认加载器2:dalvik.system.PathClassLoader[DexPathList[[zip file "/data/app/com.example.ndklearn-o6jgffmE45caOq26eG0gWg==/base.apk"],nativeLibraryDirectories=[/data/app/com.example.ndklearn-o6jgffmE45caOq26eG0gWg==/lib/arm64, /system/lib64, /system/vendor/lib64]]]>>>code == 17152125
应用程序默认加载器3:dalvik.system.PathClassLoader[DexPathList[[zip file "/data/app/com.example.ndklearn-o6jgffmE45caOq26eG0gWg==/base.apk"],nativeLibraryDirectories=[/data/app/com.example.ndklearn-o6jgffmE45caOq26eG0gWg==/lib/arm64, /system/lib64, /system/vendor/lib64]]]>>>code == 17152125
系统类加载器:dalvik.system.PathClassLoader[DexPathList[[directory "."],nativeLibraryDirectories=[/system/lib64, /system/vendor/lib64, /system/lib64, /system/vendor/lib64]]]>>>code == 190042994
------------------------------------------------------------------------------------------------------------------
打印应用程序默认加载器的委派机制:
类加载器:dalvik.system.PathClassLoader[DexPathList[[zip file "/data/app/com.example.ndklearn-o6jgffmE45caOq26eG0gWg==/base.apk"],nativeLibraryDirectories=[/data/app/com.example.ndklearn-o6jgffmE45caOq26eG0gWg==/lib/arm64, /system/lib64, /system/vendor/lib64]]]
类加载器:java.lang.BootClassLoader@c692ed4
------------------------------------------------------------------------------------------------------------------
打印系统加载器的委派机制:
类加载器:dalvik.system.PathClassLoader[DexPathList[[directory "."],nativeLibraryDirectories=[/system/lib64, /system/vendor/lib64, /system/lib64, /system/vendor/lib64]]]
类加载器:java.lang.BootClassLoader@c692ed4
activity创建过程:
ContextImpl appContext = createBaseContextForActivity(r);
Activity activity = null;
try {
java.lang.ClassLoader cl = appContext.getClassLoader();
activity = mInstrumentation.newActivity(
cl, component.getClassName(), r.intent);
StrictMode.incrementExpectedActivityCount(activity.getClass());
r.intent.setExtrasClassLoader(cl);
r.intent.prepareToEnterProcess();
if (r.state != null) {
r.state.setClassLoader(cl);
}
}
1.凡是属于android系统的类,都是由bootclassloader来加载,如:Application,Activity
2.凡是自定义类,都是pathclassloader来加载,如:MyApplication,MyActivity
3.MainActivity.class.getclassloader 等于 this.getclass().getclassloader 等于MainActivity.this.getclass().getclassloader。
表示的是,加载MainActivity.class这个类的classloader是什么,
通过activity的实例化研究我们发现,在ActivityThread.performLaunchActivity里。实例化activity用的classloader,为appContext的classloader。
4.demo中getClassloader,实际调用到contextwrraper,再调用到contextImpl的getclassloader.熟悉activity创建过程就明白,上面的appcontext就是activity的contextImpl实例
所以,就会理解getclassloader和MainActivity.class.getclassloader为什么会一致了
5.Classloader.getsystemclassloader实际也是返回pathclassloader,但是这个classloader用的极少,后面再做分析
1.classloader作用就是查找加载类。
classloader加载类采用双亲委托模式,loadclass向上委托,findclass向下查找
ClassLoader.java
protected Class<?> loadClass(String name, boolean resolve)
throws ClassNotFoundException
{
// First, check if the class has already been loaded 找缓存
Class<?> c = findLoadedClass(name);
if (c == null) {
try {
if (parent != null) {
c = parent.loadClass(name, false);
} else {
c = findBootstrapClassOrNull(name);
}
} catch (ClassNotFoundException e) {
// ClassNotFoundException thrown if class not found
// from the non-null parent class loader
}
if (c == null) {
// If still not found, then invoke findClass in order
// to find the class.
c = findClass(name);
}
}
return c;
}
一般情况下,classloader的子类,不会覆写loadclass方法。只会覆写findclass方法
比如我们熟悉的BaseDexClassLoader.java 没有覆写loadclass,findclass方法如下
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
List<Throwable> suppressedExceptions = new ArrayList<Throwable>();
Class c = pathList.findClass(name, suppressedExceptions);
if (c == null) {
ClassNotFoundException cnfe = new ClassNotFoundException(
"Didn't find class \"" + name + "\" on path: " + pathList);
for (Throwable t : suppressedExceptions) {
cnfe.addSuppressed(t);
}
throw cnfe;
}
return c;
}
继续查看DexPathList的findclass方法
public Class<?> findClass(String name, List<Throwable> suppressed) {
for (Element element : dexElements) {
Class<?> clazz = element.findClass(name, definingContext, suppressed);
if (clazz != null) {
return clazz;
}
}
if (dexElementsSuppressedExceptions != null) {
suppressed.addAll(Arrays.asList(dexElementsSuppressedExceptions));
}
return null;
}
Element是DexPathList的内部类,继续查看
public Class<?> findClass(String name, ClassLoader definingContext,
List<Throwable> suppressed) {
return dexFile != null ? dexFile.loadClassBinaryName(name, definingContext, suppressed)
: null;
}
继续查看同包下的DexFile.java
public Class loadClassBinaryName(String name, ClassLoader loader, List<Throwable> suppressed) {
return defineClass(name, loader, mCookie, this, suppressed);
}
private static Class defineClass(String name, ClassLoader loader, Object cookie,
DexFile dexFile, List<Throwable> suppressed) {
Class result = null;
try {
result = defineClassNative(name, loader, cookie, dexFile);
} catch (NoClassDefFoundError e) {
if (suppressed != null) {
suppressed.add(e);
}
} catch (ClassNotFoundException e) {
if (suppressed != null) {
suppressed.add(e);
}
}
return result;
}
private static native Class defineClassNative(String name, ClassLoader loader, Object cookie,
DexFile dexFile)
最终通过native方法加载出class
Bootclassloader是Classloader的内部类,是android中所有classloader的parent,可见性为包内可见,但是我们无法使用
在Android系统启动时创建,用于加载一些Framework层的类。
bootclassloader创建于zygoteInit的main方法的preload函数开始
1.main方法内
2.preload内
3.preloadClasses内。注意此时loader为null
4.forName方法内
到此,BootClassloader就创建完成了,并且它是一个单例,
pathclassloader主要用于加载 已经安装到android系统中的apk文件以及系统类(/data/app 目录),是android默认使用的类加载器
在App启动的时候创建,主要用于加载/data/app/xxx.xxx.xxx/sample-1/base.apk里面的类以及系统类
(实际上也可以加载外部apk,8.0以后更是更DexClassLoader完全一样了)
PathclassLoader创建分为两种,一种是systemserver进程的创建,一种是应用程序进程中的创建,
1.先看应用程序进程中pathclassloader创建过程。
肯定从应用启动流程中找,看图
1.从 handleBindApplication()开始
app = data.info.makeApplication(data.restrictedBackupMode, null);
2.LoadedApk的makeApplication方法
3.LoadedApk的getClassLoader方法
@UnsupportedAppUsage
public ClassLoader getClassLoader() {
synchronized (this) {
if (mClassLoader == null) {
createOrUpdateClassLoaderLocked(null /*addedPaths*/);
}
return mClassLoader;
}
}
4.LoadedApk的 createOrUpdateClassLoaderLocked方法
5.ApplicationLoaders的getClassLoader方法
6.ClassloaderFactory的createClassLoader方法
public static ClassLoader createClassLoader(String dexPath,
String librarySearchPath, String libraryPermittedPath, ClassLoader parent,
int targetSdkVersion, boolean isNamespaceShared, String classloaderName) {
final ClassLoader classLoader = createClassLoader(dexPath, librarySearchPath, parent,
classloaderName);
boolean isForVendor = false;
for (String path : dexPath.split(":")) {
if (path.startsWith("/vendor/")) {
isForVendor = true;
break;
}
}
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "createClassloaderNamespace");
String errorMessage = createClassloaderNamespace(classLoader,
targetSdkVersion,
librarySearchPath,
libraryPermittedPath,
isNamespaceShared,
isForVendor);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
if (errorMessage != null) {
throw new UnsatisfiedLinkError("Unable to create namespace for the classloader " +
classLoader + ": " + errorMessage);
}
return classLoader;
}
public static ClassLoader createClassLoader(String dexPath,
String librarySearchPath, ClassLoader parent, String classloaderName) {
if (isPathClassLoaderName(classloaderName)) {
return new PathClassLoader(dexPath, librarySearchPath, parent);
} else if (isDelegateLastClassLoaderName(classloaderName)) {
return new DelegateLastClassLoader(dexPath, librarySearchPath, parent);
}
throw new AssertionError("Invalid classLoaderName: " + classloaderName);
}
最终是通过ClassloaderFactory的工厂方法构建成的
2.再看systemserver进程中pathclassloader创建过程(ams所在进程,非app应用进程)
patchclassloader的创建过程,也是从zygoteinit类开始的。
forksystemserver中
handlesystemserver是在子进程中被调用的,就是刚启动的这个程序
createPathClassLoader中
经过重重的重载方法,最后new出来了一个PathClassLoader.
它和pathclassloader,都继承自BaseDexClassLoader.
android用于插件化,热修复,主要就是依靠的dexclassloader。
PathClassLoader 和 DexClassLoader 都能加载外部的 dex/apk,只不过区别是 DexClassLoader 可以指定 optimizedDirectory,
也就是 dex2oat 的产物 .odex 存放的位置,而 PathClassLoader 只能使用系统默认位置。但是这个 optimizedDirectory 在 Android 8.0 以后也被舍弃了,
只能使用系统默认的位置了。
8.0以前DexClassLoader构造
public DexClassLoader(String dexPath, String optimizedDirectory,
String librarySearchPath, ClassLoader parent) {
super(dexPath, new File(optimizedDirectory), librarySearchPath, parent);
}
8.0之后,DexClassLoader也变成PathClassLoader一样了
public DexClassLoader(String dexPath, String optimizedDirectory,
String librarySearchPath, ClassLoader parent) {
super(dexPath, null, librarySearchPath, parent);
}
public PathClassLoader(String dexPath, String librarySearchPath, ClassLoader parent) {
super(dexPath, null, librarySearchPath, parent);
}
热修复的原理是
1.取出旧的Pathclassloader的 pathlist,再取出其中的的dexElementsA[].
2.用一个新的classloader,加载出dex,再同样取出dexElementsB[].
3.把这B放在A之前,就能简单的做热修复了
因csdn对代码块支持较好,现将博客搬至csdn。个人主页:https://blog.csdn.net/zxylv
今天整理一下关于日期格式化的内容,开发中时间总要根据我们的需要去显示不同的格式,我们可以利用java.text.SimpleDateFormat,所谓格式转换,肯定是根据模型转化出我们想要的时间格式,首先我们先看一下模型中各个参数的含义吧,胸API文档中看到这样一个表格SymbolMeaningPresentationExampl_android 年月日 格式化
The MAXTime Limit: 4000/2000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 2060 Accepted Submission(s): 895Problem DescriptionGiving N integers, V1,
模仿天猫官网后端JEE模范天猫官网SSH模范天猫官网SSM模仿天猫官网SpringBoot模仿天猫官网前端一本糊涂账Java项目
目录4.1 什么是面向切面编程4.2 通过切点来选择连接点4.3 使用注解创建切面4.4 在XML中声明切面4.5 注入AspectJ切面4.6 小结在软件开发中,散布于应用中多处的功能被称为横切关注点(cross cutting concern)。通常来讲,这些横切关注点从概念上是与应用的业务逻辑相分离的(但是往往会直接嵌入到应用的业务逻辑之中)。把这些横切关注点与..._,spring还引入了一个新的bean()指示器
#include<iostream>#include<cstring>#include<cstdio>#include<algorithm>using namespace std;const int N=1e5+10;struct SUM{ int times,num; bool operator <(const SUM &t)const { if(times!=t.times)retur.._外卖店优先级c++
在前面几篇教程中我们已经实现了订阅map话题,这篇我们主要就是实现rviz中的设置目标点和初始点的功能一,实现效果:在地图上选点后librviz就会自动进行变换,发布目标点信息实现如下:可以发现控制台提示已经发布了位置点话题:在下一篇博客继续实现完整导航功能二,核心代码其实核心代码也就两三句,但是目前网上关于librviz的资料少之又少,连官方都没有api说明,只有最简单的一个de......_rviz界面怎么设置导航目的地
1,jsp 1,概念 2,jsp的三种方式 out.write(65);字符 字符串 字符数组1) <% 中间写java代码 out.println("任何类型"); out.write(65); response.getWriter().println(); response.getWrite...
Vue -> 解决 vue-ueditor-wrap 不能显示的问题_vue-ueditor-wrap不显示
错误:可以看到虚拟机卡在这里不动了错误原因:误将SELINUX的配置修改到SELINUXTYPE解决方法:重新启动虚拟机,在启动页面按e,进入grub界面然后在红线(UTF-8之后)位置输入selinux=0Ctrl+x 就可以正常进入虚拟机,再把之前修改错误的配置文件改正保存reboot重新启动虚拟机这样就关闭了SELinux..._selinux 改错了 怎么启动虚拟机
创业类文章在博客园是细水长流而不绝的,我也来谈谈我赚的第一桶金吧,涉足的行业虽然与咱们的技术不太贴,但怎么着也属于IT范畴——网游——私服~。 准确来说我的故事算不上创业,只能说是迷迷糊糊地被钱砸醒了,这听起来很不错是吧。 我以此文来怀念一下那段时光,并揭示一下自己当时不可告人的恶行,哈哈。 文章比较长、比较琐碎,我尽量说得有趣点,预防瞌睡,打起精神来吧,某些地方自认还是比较精彩的。 背景 ...
排名不分先后CSDN博文精选:Android系列开发博客资源汇总很多已经和下面的有了重复老罗的Android之旅(CSDN)《Android系统源代码情景分析》一书的作者,研究系统源码。【核心分析】maxleng的专栏又一位Android核心分析,不过已经不在更新了Android中文Wiki提供Android的中文api,还有其他_android 开发牛人博客