目录:
- 1. 反射类型包装
- 2. 实例
- 3. 总结
1. 反射类型包装
2. 实例分析
https://wos.58cdn.com.cn/IjGfEdCbIlr/ishare/video_XUU713V9XdWc37XUXU35U5d3VaV95ad1.mp4
看看其反射相关输出:
04-06 10:41:31.722 29160 29160 I kuang : load mappingClass: mirror.dalvik.system.VMRuntime ,realClass: dalvik.system.VMRuntime
04-06 10:41:31.722 29160 29160 I kuang : field: TYPE
04-06 10:41:31.722 29160 29160 I kuang : static field type: class java.lang.Class
04-06 10:41:31.722 29160 29160 I kuang : field: getCurrentInstructionSet
04-06 10:41:31.722 29160 29160 I kuang : static field type: class mirror.RefStaticMethod
04-06 10:41:31.722 29160 29160 I kuang : field: getRuntime
04-06 10:41:31.722 29160 29160 I kuang : static field type: class mirror.RefStaticMethod
04-06 10:41:31.722 29160 29160 I kuang : field: is64Bit
04-06 10:41:31.722 29160 29160 I kuang : static field type: class mirror.RefMethod
04-06 10:41:31.722 29160 29160 I kuang : field: setTargetSdkVersion
04-06 10:41:31.722 29160 29160 I kuang : static field type: class mirror.RefMethod
04-06 10:41:31.722 29160 29160 I kuang : invoke static method: getRuntime
04-06 10:41:31.722 29160 29160 I kuang : invoke method: dalvik.system.VMRuntime, method: setTargetSdkVersion
...
04-06 10:37:11.534 26426 26448 I kuang : load mappingClass: mirror.com.android.internal.content.NativeLibraryHelper ,realClass: com.android.internal.content.NativeLibraryHelper
04-06 10:37:11.534 26426 26448 I kuang : field: TYPE
04-06 10:37:11.534 26426 26448 I kuang : static field type: class java.lang.Class
04-06 10:37:11.534 26426 26448 I kuang : field: copyNativeBinaries
04-06 10:37:11.534 26426 26448 I kuang : static field type: class mirror.RefStaticMethod
04-06 10:37:11.534 26426 26448 I kuang : field: findSupportedAbi
04-06 10:37:11.534 26426 26448 I kuang : static field type: class mirror.RefStaticMethod
04-06 10:37:11.534 26426 26448 I kuang : invoke static method: findSupportedAbi
04-06 10:37:11.556 26426 26448 I kuang : invoke static method: copyNativeBinaries
04-06 10:37:12.068 26426 26448 I kuang : invoke method: android.content.res.AssetManager, method: addAssetPath
04-06 10:37:12.075 26426 26448 I kuang : invoke method: android.content.res.AssetManager, method: addAssetPath
我们来找一个简单的类看一下,NativeLibraryHelper,原始类 (Android 7.0):
package com.android.internal.content;
public class NativeLibraryHelper {
public static int copyNativeBinaries(Handle handle, File sharedLibraryDir, String abi) {
for (long apkHandle : handle.apkHandles) {
int res = nativeCopyNativeBinaries(apkHandle, sharedLibraryDir.getPath(), abi,
handle.extractNativeLibs, HAS_NATIVE_BRIDGE);
if (res != INSTALL_SUCCEEDED) {
return res;
}
}
return INSTALL_SUCCEEDED;
}
public static int findSupportedAbi(Handle handle, String[] supportedAbis) {
int finalRes = NO_NATIVE_LIBRARIES;
for (long apkHandle : handle.apkHandles) {
final int res = nativeFindSupportedAbi(apkHandle, supportedAbis);
if (res == NO_NATIVE_LIBRARIES) {
// No native code, keep looking through all APKs.
} else if (res == INSTALL_FAILED_NO_MATCHING_ABIS) {
// Found some native code, but no ABI match; update our final
// result if we haven\'t found other valid code.
if (finalRes < 0) {
finalRes = INSTALL_FAILED_NO_MATCHING_ABIS;
}
} else if (res >= 0) {
// Found valid native code, track the best ABI match
if (finalRes < 0 || res < finalRes) {
finalRes = res;
}
} else {
// Unexpected error; bail
return res;
}
}
return finalRes;
}
public static class Handle implements Closeable {
public static Handle create(File packageFile) throws IOException {
try {
final PackageLite lite = PackageParser.parsePackageLite(packageFile, 0);
return create(lite);
} catch (PackageParserException e) {
throw new IOException("Failed to parse package: " + packageFile, e);
}
}
}
}
ADocker 镜像类:
package mirror.com.android.internal.content;
public class NativeLibraryHelper {
// 加载映射 class
public static Class<?> TYPE = RefClass.load(NativeLibraryHelper.class, "com.android.internal.content.NativeLibraryHelper");
// 带参静态方法,参数无需反射
@MethodParams({Handle.class, File.class, String.class})
public static RefStaticMethod<Integer> copyNativeBinaries;
// 带参静态方法,参数无需反射
@MethodParams({Handle.class, String[].class})
public static RefStaticMethod<Integer> findSupportedAbi;
// 静态内部类
public static class Handle {
// 加载映射 class
public static Class<?> TYPE = RefClass.load(Handle.class, "com.android.internal.content.NativeLibraryHelper$Handle");
// 带参静态方法,参数无需反射
@MethodParams({File.class})
public static RefStaticMethod<Object> create;
}
}
// 封装的工具映射类,属性和方法都是静态,内部实现再通过是否传入 object, 来决定是否是普通方法还是静态方法
public class VMRuntime {
public static Class<?> TYPE = RefClass.load(VMRuntime.class, "dalvik.system.VMRuntime");
// 获取 VMRuntime 对象(单例对象)
public static RefStaticMethod<Object> getRuntime;
@MethodParams({int.class})
public static RefMethod<Void> setTargetSdkVersion;
public static RefMethod<Boolean> is64Bit;
public static RefStaticMethod<String> getCurrentInstructionSet;
}
ADocker 调用:
package com.android.dockercore.helper.compat;
public class NativeLibraryHelperCompat {
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
private static int copyNativeBinariesAfterL(File apkFile, File sharedLibraryDir) {
try {
// 调用镜像内部类 NativeLibraryHelper.Handle 的静态方法 create() 获取 handle 对象
Object handle = NativeLibraryHelper.Handle.create.call(apkFile);
if (handle == null) {
return -1;
}
String abi = null;
Set<String> abiSet = getABIsFromApk(apkFile.getAbsolutePath());
if (abiSet == null || abiSet.isEmpty()) {
return 0;
}
// step1: 调用镜像类 VMRuntime 的静态方法 getRuntime.call() 获取 VMRuntime 单例对象 // step2: 调用镜像类 vmRuntimeObject 的普通方法 is64Bit.call(vmRuntimeObject)
boolean is64Bit = VMRuntime.is64Bit.call(VMRuntime.getRuntime.call());
if (is64Bit && isVM64(abiSet)) {
if (Build.SUPPORTED_64_BIT_ABIS.length > 0) {
// 调用镜像类 NativeLibraryHelper 的静态方法 findSupportedAbi(), 传入参数 handle 对象和常量 int abiIndex = NativeLibraryHelper.findSupportedAbi.call(handle, Build.SUPPORTED_64_BIT_ABIS);
if (abiIndex >= 0) {
abi = Build.SUPPORTED_64_BIT_ABIS[abiIndex];
}
}
} else {
if (Build.SUPPORTED_32_BIT_ABIS.length > 0) {
int abiIndex = NativeLibraryHelper.findSupportedAbi.call(handle, Build.SUPPORTED_32_BIT_ABIS);
if (abiIndex >= 0) {
abi = Build.SUPPORTED_32_BIT_ABIS[abiIndex];
}
}
}
if (abi == null) {
VLog.e(TAG, "Not match any abi [%s].", apkFile.getPath());
return -1;
}
// 调用镜像类 NativeLibraryHelper 的静态方法 copyNativeBinaries(), 传入参数 handle 对象、字符串、常量
return NativeLibraryHelper.copyNativeBinaries.call(handle, sharedLibraryDir, abi);
} catch (Throwable e) {
VLog.d(TAG, "copyNativeBinaries with error : %s", e.getLocalizedMessage());
e.printStackTrace();
}
return -1;
}
}
流程图:
变量的调用(设置属性):
// 修改 mBasePackageName 内的值,传输 context 对象(原始反射的对象,一般是单例),hostPkg 参数
ContextImpl.mBasePackageName.set(context, hostPkg);
3. 总结
- 声明式。反射哪个类,哪个成员对象,哪个方法,都是用声明的方式给出的。什么是声明?就是用类定义的方式,直截了当的定义出来。
- 使用简单,没有胶水代码。在声明里,完全看不到任何和反射API相关的代码,基本隐藏了Java的反射框架,对使用者来说,几乎是无感的。
- 实现简洁,原理简单。这么一个好用的框架,它的实现却不复杂,源码不多,代码实现很简单,却很好地诠释了什么叫优雅。