中文 | English
An auxiliary tool implemented through AGP
for obtaining instances of interfaces or abstract classes between multiple modules in an Android project.
By adding the @Discoverable
annotation to an interface or abstract class and the @Implementation
annotation to an implementation class, you can use the Discoveries
class to obtain instances of that interface or abstract class from any module in the project, assisting developers in accessing data between modules.
Compared to routing frameworks like ARouter
, Discovery
primarily works during compile-time, offering better performance. It provides only service discovery functionality, allowing developers to implement richer functionalities.
Compared to ServiceLoader
, Discovery
supports abstract classes and allows obtaining the class
object of the implementation class, making it compatible with a wider range of other frameworks.
Demo project: https://github.com/xiazunyang/DiscoveryDemo.git
Discovery
scans each class file at compile time and registers information about all marked classes through ASM
to the Discoveries
class.
-
Add the following code to the appropriate location in the
build.gradle
file of theapp
module in the Android project:plugins { ... id("cn.numeron.discovery") version "2.0.0" }
-
Add the following code to the
build.gradle
file of the base module in the Android project:dependencies { ... api("cn.numeron:discovery.library:2.0.0") }
-
Obtain business services from other modules
- Mark the interface with the
@Discoverable
annotation
@Discoverable interface ISignInService { /** Check if the user is signed in */ suspend fun isSignIn(context: Context): Boolean /** Sign in with username and password */ suspend fun signInByPassword(username: String, password: String) }
- Implement the interface in any module, requiring a no-argument constructor, and mark it with the
@Implementation
annotation
@Implementation class SignInServiceImpl: ISignInService { override suspend fun isSignIn(context: Context): Boolean { TODO("Check if the user is signed in") } override suspend fun signInByPassword(username: String, password: String) { TODO("Sign in with the provided credentials") } }
- Obtain an instance of the interface using
Discoveries
in any module
lifecycleScope.launch { val signInService = Discoveries.getInstance<ISignInService>() if (!signInService.isSignIn(requireContext())) { // Not signed in, do something... } }
- Mark the interface with the
-
Obtain all instances from all modules
- Declare the initialization interface in the base module
@Discoverable interface IInitializer { fun init(application: Application) }
- Implement the interface in other modules
// Initialization for Module A @Implementation(order = 0) class AModuleInitializer: IInitializer { override fun init(application: Application) { // Initialize module A } } // Initialization for Module B @Implementation(order = 10) class BModuleInitializer: IInitializer { override fun init(application: Application) { // Initialize module B } }
- Obtain all instances and initialize them in the
Application
class
class MyApplication: Application() { override fun onCreate() { // Obtain all instances of IInitializer and call the init method val initializerList = Discoveries.getAllInstances<IInitializer>() initializerList.forEach { // Initialize modules with lower order values first it.init(this) } } }
-
2.0.0
- Update the Gradle version to 8.0.
-
1.4.2
- Fix the issue where it fails to get the implementation class that inherits from an abstract class.
- View old documentation
-
1.4.1
- Add the
order
property to theImplementation
annotation for sorting implementation classes.
- Add the
-
1.4.0
- Add support for abstract classes, no longer requiring parameters to be interfaces.
- No longer enforce implementation classes to have a no-argument constructor, but
Discovery
no longer participates in creating instances of such implementation classes. - Add two methods to
Discoveries
for obtaining theClass
of implementation classes, facilitating users to create their instances.
-
1.3.3
- When
getAllInstances
doesn't retrieve any instances, it no longer throws an exception but instead returns an empty list.
- When
-
1.3.2
- Downgrade
ASM
'sOption
toASM7
.
- Downgrade
-
1.3.1
- Fix the issue where incorrect code was woven by
ASM
.
- Fix the issue where incorrect code was woven by
-
1.3.0- Critical error exists, please use version
1.3.1
- Remove the annotation processor module, simplifying the configuration. View the previous configuration process
- Fix some issues with incremental compilation.
- Critical error exists, please use version
-
1.2.2
- Use strings as configuration names, eliminating the need for verbose imports.
- Compile-time check of classes marked with
Implementation
, requiring a no-argument constructor.
-
1.2.1
- When a class marked with
Implementation
implements multiple interfaces, it now ignores interfaces not marked withDiscoverable
.
- When a class marked with
-
1.2.0
- Add configuration options for
Discovery
to configure how implementation classes are processed. - Defaults to
Scan
mode, scanning globally. Can be configured toMark
mode, requiring the use of theImplementation
annotation to mark implementation classes, skipping the scanning process to save compilation time.
- Add configuration options for
-
1.1.0
- Add an
APT
implementation to the annotation processor, making it compatible with Java projects, along withKSP
.
- Add an
-
1.0.0
- Official release, implemented primarily with
KSP
andAGP
.
- Official release, implemented primarily with