最近在了解Android组件化开发相关模式,在组件间通信和服务相互调用的时候,除了ARouter,意外发现了ServiceLoader这个类,便抽时间了解了一下,并写了Demo尝试了一下,确实是挺方便的一个类
那么ServiceLoader
到底是用来干什么的呢?
其实我们经常做的事情,就是根据一个类去找他的父类或者接口,那么ServiceLoader
就是帮助我们做反向操作的一个类,根据一个接口去找它所有的实现类
以下讲解都是基于两个不同组件之间相互调用,接下来我们主要距离在组件HomeModel
依赖库中调用主工程App
中的服务,以及反过来相互调用的过程
使用其实很简单:
- 新建一个
HomeModel
的依赖库,让App
依赖HomeModel
- 建立一个
ContentService
的接口 - 我们只需要在建立一个与Java目录平级的一个目录
resources/META-INF/services/
,然后建立一个txt,命名为com.gx.aidl.inter.ContentService
,ServiceLoader
会自己匹配到,如下:
然后在主App
工程和组件工程HomeModel
中各自实现ContentService的接口,如下:
App
工程:
class AppContentServiceImpl : ContentService {
override fun getName(): String = "AppModule"
override fun init(context: Context) {
Log.e("gex", "AppContentServiceImpl init : $context")
}
}
HomeModel
依赖库:
class ContentServiceImpl : ContentService {
override fun getName(): String = "HomeModel"
override fun init(context: Context) {
Log.e("Gex", "ContentServiceImpl init: $context")
}
}
两个同城下都要建立resources/META-INFO/services
的目录,并建立相应的txt文件,txt文件里边各自写自己工程的实现类.如下:
com.gx.aidl.AppContentServiceImpl
com.gx.aidl.impl.ContentServiceImpl
然后我们在主工程和HomeModel
工程各自通过ServiceLoader来获取相关的实现类,代码如下:
//App工程的代码
private fun initService() {
var loader: ServiceLoader<ContentService>? = ServiceLoader.load(ContentService::class.java)
loader?.forEach {
it?.init(this)
Log.e("Gex", "AppModel ModelName : ${it?.getName()}")
}
}
//HomeModel工程的代码,我们会过滤掉当前model中的实现类,只输出App主工程的实现类
private fun initService() {
val loader: ServiceLoader<ContentService>? = ServiceLoader.load(ContentService::class.java)
loader?.forEach {
if(it !is ContentService){
it.init(this)
Log.e("Gex", "HomeActivity ModelName : ${it.getName()}")
}
}
}
接下来我们运行起来看下结果,在App主工程中会扫描到两个工程中所有的实现类,并可以调用相关方法:
AppContentServiceImpl init : com.gx.aidl.MainActivity@3f471dd3
AppModel ModelName : AppModule
ContentServiceImpl init: com.gx.aidl.MainActivity@3f471dd3
AppModel ModelName : HomeModel
接下来我们调转到组件HomeModel
中的HomeActivity,在依赖库中调用主工程中的方法,运行结果如下:
AppContentServiceImpl init : com.gx.aidl.HomeActivity@2aedfb64
HomeActivity ModelName : AppModule
我们可以看到组件依赖库工程完全可以拿到主工程App
下的AppContentServiceImpl
的实现。同理,如果我们项目组件化开发的化,是不是就可以组件之间相互调用各自的服务了呢!
另外我们是不是可以把我们的业务组件模块写活了呢,比如图片加载和网络请求,我们的组件只需要调用相关方法,图片加载库和网络请求库可以由不同的使用方按照我们的规则采用不同的加载库,比如Glide
,Fresco
,OkHttp
,Retrofit
,Socket
等
interface GxProvider {
fun init(context: Context)
}
interface ContentService : GxProvider {
fun getName(): String
fun setImageUri(imageView: ImageView,pic:String)
}
class AppContentServiceImpl : ContentService {
override fun setImageUri(imageView: ImageView, pic: String) {
//Fresco 加载图片
}
override fun getName(): String = "AppModule"
override fun init(context: Context) {
Log.e("gex", "AppContentServiceImpl init : $context")
}
}
class ContentServiceImpl : ContentService {
override fun setImageUri(imageView: ImageView, pic: String) {
//Glide 加载图片
}
override fun getName(): String = "HomeModel"
override fun init(context: Context) {
Log.e("Gex", "ContentServiceImpl init: $context")
}
}
最近处于一个空闲期,就多了解一些知识,突然发现感觉要学的东西还是有很多的啊 ,静下心来,埋头学习,不断进步!