房间和改造中的接口
Interface in Room and Retrofit
使用 retrofit 库时,您创建了一个 接口,其中包含具有所有端点的函数,但您从未在任何地方实现它。我的问题是这个接口是在哪里实现的?我在使用 android Room
创建 DAO 时注意到相同的模式
他们使用两种不同的方法,Retrofit 利用 Java 反射 proxy 这是一种在运行时实现接口的工具,您的代理的 invoke
方法将检索调用的方法方案通过反思,并可以在此基础上工作。事实上,改造只能使用方法元数据。
代理是一种从接口创建对象的方法,无需使用代码实现它们,而是通过简单地获取这些参数的单个调用方法
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
Log.d("proxyCall", method.getName());
return Response (...);
}
您还可以从方法中获取其他信息(比如它的注释,例如 @GET 等)
另一方面,Room 在编译期间使用 annotation processors 生成代码(您添加它的处理器 a.k.a。编译器在 gradle 配置中使用 annotationProcessor
或kapt
)。
您可以在模块的 build
文件夹中找到 Room 生成的源代码。
Retrofit 使用 Java 动态代理方法在运行时创建 类,这需要一个接口,因此您只需定义您的接口,retrofit 将构建一个类型安全的实现您在运行时的界面。
房间数据库同时使用注释处理器和反射。它使用注释处理器为注释为 @DAO
和 @Database
的 class 生成 Java 代码,并生成带有 _Impl
后缀的实现 class。
它使用反射来查找数据库实现 class。当你调用 Room.databaseBuilder(context, AppDatabase.class, databaseName).build();
时,它会这样调用,后缀的值为 _Impl
@NonNull
static <T, C> T getGeneratedImplementation(Class<C> klass, String suffix) {
final String fullPackage = klass.getPackage().getName();
String name = klass.getCanonicalName();
final String postPackageName = fullPackage.isEmpty()
? name
: (name.substring(fullPackage.length() + 1));
final String implName = postPackageName.replace('.', '_') + suffix;
//noinspection TryWithIdenticalCatches
try {
@SuppressWarnings("unchecked")
final Class<T> aClass = (Class<T>) Class.forName(
fullPackage.isEmpty() ? implName : fullPackage + "." + implName);
return aClass.newInstance();
} catch (ClassNotFoundException e) {
throw new RuntimeException("cannot find implementation for "
+ klass.getCanonicalName() + ". " + implName + " does not exist");
} catch (IllegalAccessException e) {
throw new RuntimeException("Cannot access the constructor"
+ klass.getCanonicalName());
} catch (InstantiationException e) {
throw new RuntimeException("Failed to create an instance of "
+ klass.getCanonicalName());
}
}
房间限制了反射的使用,所以房间的速度受反射的影响不大
使用 retrofit 库时,您创建了一个 接口,其中包含具有所有端点的函数,但您从未在任何地方实现它。我的问题是这个接口是在哪里实现的?我在使用 android Room
创建 DAO 时注意到相同的模式他们使用两种不同的方法,Retrofit 利用 Java 反射 proxy 这是一种在运行时实现接口的工具,您的代理的 invoke
方法将检索调用的方法方案通过反思,并可以在此基础上工作。事实上,改造只能使用方法元数据。
代理是一种从接口创建对象的方法,无需使用代码实现它们,而是通过简单地获取这些参数的单个调用方法
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
Log.d("proxyCall", method.getName());
return Response (...);
}
您还可以从方法中获取其他信息(比如它的注释,例如 @GET 等)
另一方面,Room 在编译期间使用 annotation processors 生成代码(您添加它的处理器 a.k.a。编译器在 gradle 配置中使用 annotationProcessor
或kapt
)。
您可以在模块的 build
文件夹中找到 Room 生成的源代码。
Retrofit 使用 Java 动态代理方法在运行时创建 类,这需要一个接口,因此您只需定义您的接口,retrofit 将构建一个类型安全的实现您在运行时的界面。
房间数据库同时使用注释处理器和反射。它使用注释处理器为注释为 @DAO
和 @Database
的 class 生成 Java 代码,并生成带有 _Impl
后缀的实现 class。
它使用反射来查找数据库实现 class。当你调用 Room.databaseBuilder(context, AppDatabase.class, databaseName).build();
时,它会这样调用,后缀的值为 _Impl
@NonNull
static <T, C> T getGeneratedImplementation(Class<C> klass, String suffix) {
final String fullPackage = klass.getPackage().getName();
String name = klass.getCanonicalName();
final String postPackageName = fullPackage.isEmpty()
? name
: (name.substring(fullPackage.length() + 1));
final String implName = postPackageName.replace('.', '_') + suffix;
//noinspection TryWithIdenticalCatches
try {
@SuppressWarnings("unchecked")
final Class<T> aClass = (Class<T>) Class.forName(
fullPackage.isEmpty() ? implName : fullPackage + "." + implName);
return aClass.newInstance();
} catch (ClassNotFoundException e) {
throw new RuntimeException("cannot find implementation for "
+ klass.getCanonicalName() + ". " + implName + " does not exist");
} catch (IllegalAccessException e) {
throw new RuntimeException("Cannot access the constructor"
+ klass.getCanonicalName());
} catch (InstantiationException e) {
throw new RuntimeException("Failed to create an instance of "
+ klass.getCanonicalName());
}
}
房间限制了反射的使用,所以房间的速度受反射的影响不大