房间和改造中的接口

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 配置中使用 annotationProcessorkapt)。 您可以在模块的 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());
        }
    }

房间限制了反射的使用,所以房间的速度受反射的影响不大