引言
现在Android项目一般都用的是组件化,组件化完全可以自己通过反射和注解写一套。
在组件式开发时,有时在某个Module下想要使用其他Module的业务,很不方便,要不重新写一个,要么提到公共Module,ARouter直接可以解决这类问题。这就是--模块间Service通信调用。
但是,没必要重复造轮子。发现Arouter完全ok。就简单说说。
Arouter 支持模块间的路由、通信、解耦。
基础使用
配置
在moudle_common中配置的
defaultConfig {
minSdk rootProject.ext.minSdkVersion
targetSdk rootProject.ext.targetSdkVersion
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
//ARouter配置
javaCompileOptions {
annotationProcessorOptions {
arguments = [AROUTER_MOUDLE_NAME: project.getName()]
}
}
}
dependencies {
...
//路由ARouter
api 'com.alibaba:arouter-api:1.5.2'
annotationProcessor 'com.alibaba:arouter-compiler:1.5.2'
...
}
初始化
class MyApplication : Application() {
override fun onCreate() {
super.onCreate()
initARouter()
}
/**
* 初始化ARouter
*/
private fun initARouter() {
if (BuildConfig.DEBUG) {
ARouter.openLog()
// 开启调试模式(如果在InstantRun模式下运行,必须开启调试模式!线上版本需要关闭,否则有安全风险)
ARouter.openDebug()
}
ARouter.init(this)
}
override fun onTerminate() {
super.onTerminate()
//释放
ARouter.getInstance().destroy()
}
}
路由地址统一管理类 Constant
/**
* 路由表
*/
object ARouterConstant {
const val LOGIN_ACTIVITY = "/com/demo/loginActivity"
}
依赖注入
注意:这里路由地址 至少需要有两级,/xx/xx
@Route(path = ARouterConstant.LOGIN_ACTIVITY)
class TestActivity : BaseActivity(){
}
路由操作
/**
* 路由跳转 (不带参数)
*/
findViewById<Button>(R.layout.activity_login).setOnClickListener{
//路由跳转
ARouter.getInstance().build("/arouter/TestActivity").navigation()
}
/**
* 路由跳转 (带参数)
*/
private fun aRouterJump(){
//带参数
ARouter.getInstance().build(ARouterConstant.SECOND_ACTIVITY)
.withLong("long",123l)
.withString("string","路由")
.withObject("object",new TestARouterEntry("时间", TimeUtils.getCurrentTime(TimeUtils.DateMode.SIMPLE_TIME_MODE)))
.navigation()
}
代码混淆
-keep public class com.alibaba.android.arouter.routes.**{*;}
-keep public class com.alibaba.android.arouter.facade.**{*;}
-keep class * implements com.alibaba.android.arouter.facade.template.ISyringe{*;}
#如果使用了 byType 的方式获取 Service,需要添加下面规则,保护接口
#emmm还没看到这种使用方法呢,这应该是进阶用法吧(这种就是自己定义接口继承自IProvider,然后实现自己的接口的方式使用IProvider)
-keep interface * implements com.alibaba.android.arouter.facade.template.IProvider
#如果使用了 单类注入 即 不顶用接口实现IPrvider,需要要添加规则,保护实现(哦哦 就是直接实现接口IProvider的类,不是通过自己定义接口继承自IProvider,然后在实现自己的接口)
#-keep class * implements com.alibaba.android.arouter.facade.template.IProvider
进阶--》模块间Service(业务逻辑)通信调用。
在组件式开发时,有时在某个Module下想要使用其他Module的业务,很不方便,要不重新写一个,要么提到公共Module,ARouter直接可以解决这类问题。
业务接口要声明在common公共Module中
申明接口内容
package com.sum.common.service
import android.content.Context
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.Observer
import com.alibaba.android.arouter.facade.template.IProvider
/**
* @date 2023/3/25 11:29
* @desc 登录服务相关接口
* 只是定义了一个接口,提供了对外相关能力,其他模块只需要按需添加,需要在login模块实现
*/
interface ILoginService : IProvider {
/**
* 是否登录
* @return Boolean
*/
fun isLogin(): Boolean
/**
* 跳转登录页
* @param context
*/
fun login(context: Context)
/**
* 跳转隐私协议
* @param context
*/
fun readPolicy(context: Context)
/**
* 登出
* @param context
* @param lifecycleOwner
* @param observer
*/
fun logout(
context: Context,
lifecycleOwner: LifecycleOwner?,
observer: Observer<Boolean>
)
}
接口的具体实现, 在具体module下
实现代码
package com.sum.login.service
import android.content.Context
import android.content.Intent
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.Observer
import androidx.lifecycle.lifecycleScope
import com.alibaba.android.arouter.facade.annotation.Route
import com.sum.common.constant.LOGIN_SERVICE_LOGIN
import com.sum.common.model.User
import com.sum.common.provider.UserServiceProvider
import com.sum.common.service.ILoginService
import com.sum.framework.log.LogUtil
import com.sum.framework.toast.TipsToast
import com.sum.login.login.LoginActivity
import com.sum.login.policy.PrivacyPolicyActivity
import com.sum.network.manager.ApiManager
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
/**
* @date 2023/3/25 13:41
* @desc 提供对ILoginService接口的具体实现
*/
@Route(path = LOGIN_SERVICE_LOGIN)
class LoginService : ILoginService {
/**
* 是否登录
* @return Boolean
*/
override fun isLogin(): Boolean {
return UserServiceProvider.isLogin()
}
/**
* 跳转登录页
* @param context
*/
override fun login(context: Context) {
context.startActivity(Intent(context, LoginActivity::class.java))
}
/**
* 登出
*/
override fun logout(
context: Context,
lifecycleOwner: LifecycleOwner?,
observer: Observer<Boolean>
) {
val scope = lifecycleOwner?.lifecycleScope ?: GlobalScope
scope.launch {
val response = ApiManager.api.logout()
if (response?.isFailed() == true) {
TipsToast.showTips(response.errorMsg)
return@launch
}
LogUtil.e("logout${response?.data}", tag = "smy")
observer.onChanged(response?.isFailed() == true)
login(context)
}
}
/**
* 跳转隐私协议页
* @param context
*/
override fun readPolicy(context: Context) {
context.startActivity(Intent(context, PrivacyPolicyActivity::class.java))
}
override fun init(context: Context?) {
}
}
对外提供相关能力 provider
注意:provider在公共Module中
代码:
package com.sum.common.provider
import android.content.Context
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.Observer
import com.alibaba.android.arouter.facade.annotation.Autowired
import com.alibaba.android.arouter.launcher.ARouter
import com.sum.common.constant.LOGIN_SERVICE_LOGIN
import com.sum.common.service.ILoginService
/**
* @date 2023/3/26 07:30
* @desc UserService提供类,对外提供相关能力
* 任意模块就能通过LoginServiceProvider使用对外暴露的能力
*/
object LoginServiceProvider {
//val loginService = ARouter.getInstance().build(LOGIN_SERVICE_LOGIN).navigation() as? ILoginService
// [The inject fields CAN NOT BE 'private'!!! please check field [userService] in class [LoginServiceProvider]]
@Autowired(name = LOGIN_SERVICE_LOGIN)
lateinit var loginService: ILoginService
init {
ARouter.getInstance().inject(this)
}
/**
* 是否登录
* @return Boolean
*/
fun isLogin(): Boolean {
return loginService.isLogin()
}
/**
* 跳转登录页
* @param context
*/
fun login(context: Context) {
loginService.login(context)
}
/**
* 跳转隐私协议
* @param context
*/
fun readPolicy(context: Context) {
loginService.readPolicy(context)
}
/**
* 登出
* @param context
* @param lifecycleOwner
* @param observer
*/
fun logout(
context: Context,
lifecycleOwner: LifecycleOwner?,
observer: Observer<Boolean>
) {
loginService.logout(context, lifecycleOwner, observer)
}
}
模块提供服务的路由地址
代码
package com.sum.common.constant
/**
* @date 2023/3/23 18:35
* @desc 路由路径
* 命名规则:/开头并且必须大于两级,/模块/分类/具体名称
* 比如: /模块名称/组件[activity]/组件名称
* /模块名称/服务[service]/服务名称
*/
//**********************跳转相关**********************
/**
* 登录模块
*/
//登录页面
const val LOGIN_ACTIVITY_LOGIN = "/login/activity/login"
//注册页面
const val LOGIN_ACTIVITY_REGISTER = "/login/activity/register"
//隐私协议界面
const val Login_ACTIVITY_POLICY = "/login/activity/policy"
/**
* 首页模块
*/
//首页
const val MAIN_ACTIVITY_HOME = "/main/activity/home"
/**
* 用户模块
*/
//设置界面
const val USER_ACTIVITY_SETTING = "/user/activity/setting"
//设置用户信息
const val USER_ACTIVITY_INFO = "/user/activity/info"
//我的收藏界面
const val USER_ACTIVITY_COLLECTION = "/user/activity/collection"
/**
* 搜索模块-搜索页面
*/
const val SEARCH_ACTIVITY_SEARCH = "/search/activity/search"
/**
* 视频模块
*/
const val VIDEO_ACTIVITY_PLAYER = "/video/activity/player"
/**
* Demo模块
*/
//Navigation
const val DEMO_ACTIVITY_NAVIGATION = "/demo/activity/navigation"
//Lifecycle
const val DEMO_ACTIVITY_LIFECYCLE = "/demo/activity/lifecycle"
//ViewModel
const val DEMO_ACTIVITY_VIEWMODEL = "/demo/activity/viewmodel"
//LiveData
const val DEMO_ACTIVITY_LIVEDATA = "/demo/activity/livedata"
//**********************服务相关**********************
/**
* 登录模块-登录服务
*/
const val LOGIN_SERVICE_LOGIN = "/login/service/login"
/**
* 用户模块-用户服务
*/
const val USER_SERVICE_USER = "/user/service/user"
/**
* 主页模块-主页
*/
const val MAIN_SERVICE_HOME = "/main/service/home"
/**
* 搜索模块模块-搜索
*/
const val SEARCH_SERVICE_SEARCH = "/search/service/search"
使用
接下来就可以在其他Module去使用了,例如在MineModule下去使用loginModuleService,如下:
LoginServiceProvider.login(requireContext())
这样就可以直接从MineModule调用loginModule的Service了(不用写登录这块逻辑了,很好的解耦)。