如何在Android Studio中使用Gradle将Reflections库集成到保存和收集中 [英] How to integrate the Reflections library in android studio using gradle with save and collect

查看:842
本文介绍了如何在Android Studio中使用Gradle将Reflections库集成到保存和收集中的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的问题与github上@ronmamo的 Reflections 库相关,并将它集成到我的Android项目动态访问所有继承自某个接口的类。



我对gradle或maven不熟悉,所以这对我来说是一个学习过程,但我已经达到了并且不知道如何调试/找到答案。



由于@ronmamo建议这里,我想在包含所有扫描的元数据的版本上生成一个xml文件,并让我在稍后使用它的时候,代码:


尽管可以在
应用程序的引导时间轻松完成扫描,并且不需要很长时间,有时一个好主意
将Reflections集成到你的构建生命周期中。使用简单的
Maven / Gradle / SBT /无论什么配置,您都可以在编译时间后将所有已扫描的
元数据保存到xml / json文件中。稍后,当
项目启动时,您可以让Reflections收集所有
这些资源并为您重新创建该元数据,使其在运行时可以使用
,而无需重新扫描类路径 - 因此减少
的引导时间。

我不确定我完全理解这个引导在整个过程中的具体位置(根据android应用程序生命周期等甚至建立时间?),所以我不确定在哪里调用Reflections.collect()。目前我在稍后的某个时间在应用程序中调用它,当用户到达程序中的某个点时。



从几个stackoverflow帖子和git自述文件中,我([...]意味着删除无关的代码)

build.gradle(模块:应用程序):

 依赖关系{
[...]
compile'org.reflections:reflections:0.9.11'
}

build.gradle(Project:MyProject):

< pre $ buildscript {
repositories {
jcenter()
mavenCentral()
}
依赖关系{
classpath' com.android.tools.build:gradle:2.3.3'
classpath'org.reflections:reflections:0.9.11'
}
}

allprojects {
repositories {
jcenter()
}
}

任务runReflections {
doLast {
org.reflections.Reflections( FQN)。保存($ {sourceSet.main.output.classesDir} /META-INF/reflections/myproject-reflections.xml)
}
}

任务清理(类型:删除){
delete rootProject.buildDir
}

稍后在我的代码中(这个类是通过用户输入到达的,而不是在应用程序启动时加载):

pre $ Reflections reflections = Reflections.collect( );
Set< Class< ;?扩展MyInterface>> allClasses = reflections.getSubTypesOf(MyInterface.class);

由于反射没有实例化并且值为null,所以会产生以下异常:

 尝试调用虚拟方法'java.util.Set org.reflections.Reflections.getSubTypesOf(java.lang.Class)'在空对象引用

我知道生成的.xml文件驻留在构建的计算机上发生,我不知道这是否也转移到Android设备,所以我的猜测是这就是为什么失败。但是,在我的Android设备上传输并运行apk文件之前,我的Java代码在什么时候可以访问此文件?



我试图用许多不同的方式不同的角度,但我似乎无法找到一个解决方案,使Android的反射工作。我理解这里解释的原理,在构建时在xml文件中生成信息似乎更好,以便在运行时提供类信息。但是我怎样才能正确设置它?



谢谢 >这里有一点小小的鸡蛋或鸡蛋问题需要解决


  1. 您需要反射 API来访问从 src / main / java
  2. 编译的类
  3. Gradle任务和 Reflections 类由Gradle的 buildscript classloader加载

  4. src /在定义 buildscript classloader之后编译main / java


    您需要引入另一个可以访问编译类的类加载器来打破循环依赖。这可以传递给 Reflections 。例如:

      buildscript {
    classpath'org.reflections:reflections:0.9.11'
    }
    任务doReflectyStuff {
    dependsOn compileJava
    doLast {
    URL [] urls = sourceSets.main.runtimeClasspath.files.collect {
    it.toURI()。toURL()

    ClassLoader classLoader = new URLClassLoader(urls,null)
    Configuration config = new ConfigurationBuilder(com.mypackage,classLoader)
    Reflections reflections = new ReflectionsBuilder(config)
    ...
    }
    }

    请参阅这里对于类似的问题


    My question is related to the Reflections library by @ronmamo on github and integrating this into my Android project to dynamically access all classes that inherit from a certain interface.

    I am not that familiar with gradle or maven so this is a learning process for me but i have reached a roadblock and do not know how to debug / find an answer to this one.

    As @ronmamo suggests here, I want to generate a xml file on build containing all scanned metadata and let Reflections collect it later when I use it in my code:

    Although scanning can be easily done on bootstrap time of your application - and shouldn't take long, it is sometime a good idea to integrate Reflections into your build lifecyle. With simple Maven/Gradle/SBT/whatever configuration you can save all scanned metadata into xml/json files just after compile time. Later on, when your project is bootstrapping you can let Reflections collect all those resources and re-create that metadata for you, making it available at runtime without re-scanning the classpath - thus reducing the bootstrapping time.

    I am not sure I fully understand where exactly in the entire process this "bootstrapping" takes place (in terms of the android app lifecycle etc. or even build time?) so I am not certain where exactly to call Reflections.collect(). Currently I am calling it at some point later in my app when the user has reached a certain point in the program.

    From several stackoverflow posts and the git readme files, I have come up with this for now: ([...] means removed unrelated code)

    build.gradle (Module:app):

    dependencies {
        [...]
        compile 'org.reflections:reflections:0.9.11'
    }
    

    build.gradle (Project: MyProject):

    buildscript {
        repositories {
            jcenter()
            mavenCentral()
        }
        dependencies {
            classpath 'com.android.tools.build:gradle:2.3.3'
            classpath 'org.reflections:reflections:0.9.11'
        }
    }
    
    allprojects {
        repositories {
            jcenter()
        }
    }
    
    task runReflections {
        doLast {        
            org.reflections.Reflections("f.q.n").save("${sourceSet.main.output.classesDir}/META-INF/reflections/myproject-reflections.xml")
        }
    }
    
    task clean(type: Delete) {
        delete rootProject.buildDir
    }
    

    And later on in my code (this class is reached at some point through user input, not loaded on app start):

    Reflections reflections = Reflections.collect(); 
    Set<Class<? extends MyInterface>> allClasses = reflections.getSubTypesOf(MyInterface.class);
    

    This generates the following exception since "reflections" is not instantiated and has the value of "null":

    Attempt to invoke virtual method 'java.util.Set org.reflections.Reflections.getSubTypesOf(java.lang.Class)' on a null object reference
    

    I understand that the generated .xml file resides on the computer where the build is happening, and I am not sure if this is also transferred to the android device so my guess is that is why this fails. But at what point does my Java code have access to this file before the apk is transferred and run on my android device?

    I have tried googling this in many different ways from different angles but I cannot seem to find a solution to make reflections work in Android. I understand the principle explained here and it seems better to generate the information in an xml file at build time to have the class information available at runtime. But how can I set this up properly?

    Thank you

    解决方案

    There's a little bit of a chicken-or-egg problem to solve here

    1. You want Reflections API to access the classes compiled from src/main/java
    2. Gradle tasks and the Reflections classes are loaded by Gradle's buildscript classloader
    3. The classes in src/main/java are compiled after the buildscript classloader is defined

    You'll need to introduce another classloader that can access the compiled classes to break the cyclic dependency. This can then be passed to Reflections. Eg:

    buildscript {
        classpath 'org.reflections:reflections:0.9.11'
    }
    task doReflectyStuff {
        dependsOn compileJava
        doLast {
            URL[] urls = sourceSets.main.runtimeClasspath.files.collect {
                it.toURI().toURL()
            }
            ClassLoader classLoader = new URLClassLoader(urls, null)
            Configuration config = new ConfigurationBuilder("com.mypackage", classLoader)
            Reflections reflections = new ReflectionsBuilder(config)
            ...
        }
    }
    

    See here for a similar question

    这篇关于如何在Android Studio中使用Gradle将Reflections库集成到保存和收集中的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆