AndroidAOP | ModuleCommunication |
---|---|
当前项目是结合和 AndroidAOP 和 ModuleCommunication来使用的,主打一个轻量易用 ,本文不具体介绍这两个框架其他的用法,旨在介绍如何利用这两个框架配置出 类似于 ARouter 等框架的用法,如有需要点击下方链接可查看
- 基础的 Activity 跳转,Fragment 的获取
- 可获取封装好的跳转 Activity 的 Intent,你想怎么跳就怎么跳
- 支持异步跳转 Activity
- 支持无上下文跳转 Activity
- 通过 Url 打开页面
- 跳转页面中间的拦截器
- 解耦 各个 module 的
伪Application
- 暴露服务
- 自定义降级策略
- 面向切面编程,探索 AndroidAOP 的更多功能,让你代码简洁高级,为你项目赋予高级能力
- 探索 ModuleCommunication 的更多功能,让 module 之间的通信变得就像在一个 module 一样
- 结合两个库的功能,可实现纯静态代码,而不用反射。市面上的几乎没有不用反射的 Router 库吧🤔
- 够轻量,虽然轻量,但主要的Router功能基本都有了。不要看到轻量就觉得可能不好用、bug多。需要知道不一定代码多就好用,而且那么多代码你不一定都用得到
在开始之前可以给项目一个Star吗?非常感谢,你的支持是我唯一的动力。欢迎Star和Issues!
1、在 项目根目录 的 build.gradle
里依赖插件
新版本写法
buildscript {
dependencies {
//必须项 👇
classpath 'io.github.FlyJingFish.ModuleCommunication:module-communication-plugin:1.2.9'
}
}
plugins {
//必须项 👇下边版本号根据你项目的 Kotlin 版本决定👇
id 'com.google.devtools.ksp' version '1.8.10-1.0.9' apply false
//必须项 👇需要配合 AndroidAOP 使用
id 'io.github.FlyJingFish.AndroidAop.android-aop' version '2.2.5' apply true
}
或老版本写法
buildscript {
dependencies {
//必须项 👇
classpath 'io.github.FlyJingFish.ModuleCommunication:module-communication-plugin:1.2.9'
//必须项 👇
classpath 'io.github.FlyJingFish.AndroidAop:android-aop-plugin:2.2.5'
}
}
plugins {
//必须项 👇下边版本号根据你项目的 Kotlin 版本决定👇
id 'com.google.devtools.ksp' version '1.8.10-1.0.9' apply false
}
// 👇加上这句自动为所有module“预”配置debugMode
apply plugin: "android.aop"
2、在 app 的 build.gradle
添加
//必须项 👇
plugins {
...
id 'android.aop'//最好放在最后一行
}
3、在根目录的 gradle.properties
添加如下设置
对于当前路由项目来说
debugMode
就够用了,debugMode 打包速度快,如果您还用到 AndroidAOP 的其他功能,点此看具体用法
androidAop.debugMode=true
4、在 使用路由的module 的 build.gradle
里依赖插件
plugins {
id 'communication.export'
}
5、引入依赖库
dependencies {
//必须项 👇AndroidAOP 提供支持
implementation 'io.github.FlyJingFish.AndroidAop:android-aop-core:2.2.5'
implementation 'io.github.FlyJingFish.AndroidAop:android-aop-annotation:2.2.5'
//使用路径的方式跳转则必须添加(使用通信module的则不加也可以)
implementation 'io.github.FlyJingFish.ModuleCommunication:module-communication-route:1.2.9'
//这一项在你配置 communication.export 时就已经自动引入,如没有配置则需引入
implementation 'io.github.FlyJingFish.ModuleCommunication:module-communication-annotation:1.2.9'
//使用拦截器(可选项)
implementation 'io.github.FlyJingFish.ModuleCommunication:module-communication-intercept:1.2.9'
}
你可能会说了,不是说了轻量吗,怎么要加这么多依赖库?你可以数一下每个依赖库里边的代码,总的代码量是没多少的,更何况他的功能远不止一个 Router 功能哦~
路由主要用到下边两个注解
-
@Route 路由页面
-
@RouteParams 路由页面参数
- 一、配置页面
// activity
@Route("/user/UserActivity")
class UserActivity : AppCompatActivity() {
@delegate:RouteParams("params1")
val params1 :String ? by lazy(LazyThreadSafetyMode.NONE) {
intent.getStringExtra("params1")
}
@delegate:RouteParams("params2")
val params2 :User ? by lazy(LazyThreadSafetyMode.NONE) {
intent.getSerializableExtra("params2") as User
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_user)
Log.e("UserActivity","params1=$params1,params2=$params2")
}
}
//fragment
@Route("/user/UserFragment")
class UserFragment : Fragment() {
@delegate:RouteParams("params1")
val params1 :String ? by lazy(LazyThreadSafetyMode.NONE) {
arguments?.getString("params1")
}
@delegate:RouteParams("params2")
val params2 :User ? by lazy(LazyThreadSafetyMode.NONE) {
arguments?.getSerializable("params2") as User
}
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
val binding = ActivityUserBinding.inflate(inflater,container,false)
Log.e("UserFragment","params1=$params1,params2=$params2")
return binding.root
}
}
- 在其他 module 调用
跳转 Activity
//在 module-communication-route 可以使用路径跳转
ModuleRoute.builder("/user/UserActivity")
.putValue("params1","lalla")
.putValue("params2",user)
.go(this)
//加上监听
ModuleRoute.builder("user/UserActivity")
.putValue("params1","lalla")
.putValue("params2",null as Serializable?)
//想要自己处理跳转 context.startActivity()
.setOnGoActivity(object : OnGoActivity{
override fun onGo(context: Context, intent: Intent):Boolean {
//返回true 代表自己处理跳转,返回false 代表自己不处理
return false
}
})
.go(this,object :OnNavigationBack{
override fun onResult(result: NavigationResult) {
//主要是用于跳转是否成功,返回结果是失败就是找不到页面,也就不会回调上边的 OnGoActivity
}
})
//在自己的 module 下也可使用帮助类,帮助类也可跨模块调用需要使用 ModuleCommunication 的通信功能
`LibUser$$Router`.goUser_UserActivity(this,"hahah",user)
获取 Fragment
//在 module-communication-route 可以使用路径新建fragment对象,找不到类就会返回 null
val instance : Any = ModuleRoute.builder("/user/UserFragment")
.putValue("params1","lalla")
.putValue("params2",user)
.go()
instance?.let {
val fragment : Fragment = instance as Fragment
}
//在自己的 module 下也可使用帮助类,帮助类也可跨模块调用需要使用 ModuleCommunication 的通信功能
val fragment : Fragment = `LibUser$$Router`.newUser_UserFragment("lalala",user) as Fragment
按模块去加载页面,减少初始化
// builder 第一个参数传 module 名,这个名来自于帮助类 `LibUser$$Router` 的前半截
ModuleRoute.builder("LibUser","/user/UserActivity")
.putValue("params1","lalla")
.putValue("params2",user)
.go(this)
- 想要让
ModuleRoute
起作用,还需配置以下信息
object CollectApp {
private val allRouteClazz = mutableSetOf<BaseRouterClass>()
/**
* 这一步才可以收集到所有的路由路径信息
*/
@AndroidAopCollectMethod
@JvmStatic
fun collectRouterClass(sub: BaseRouterClass){
Log.e("CollectIntercept","collectRouterClass=$sub")
allRouteClazz.add(sub)
}
fun onCreate(application: Application){
Log.e("CollectIntercept","getAllRouterIntercept-size=${allRouterIntercept.size}")
//设置全部路由路径信息,这样ModuleRoute才可以起作用
ModuleRoute.autoAddAllRouteClass(allRouteClazz)
}
}
//初始化
class MyApp : Application() {
override fun onCreate() {
super.onCreate()
//一键初始化所有需要的信息
CollectApp.onCreate(this)
}
}
class SchemeDistributionActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val uri = intent.data
uri?.let {
ModuleRoute.builder(it)?.go()
}
finish()
}
}
在 AndroidManifest.xml 中配置
<activity android:name=".SchemeDistributionActivity"
android:exported="true">
<!-- Scheme -->
<intent-filter>
<data
android:host="test.flyjingfish.com"
android:scheme="lightrouter"/>
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.BROWSABLE"/>
</intent-filter>
</activity>
ModuleRoute 会自动解析 uri ,会根据您当初设置的各项参数去解析跳转页面的参数,并且不限制类型,除了8种基本数据类型和String类型之外,其他的对象类型你只需要把对象数据转化为Json数据即可,例如
<script type="text/javascript">
function onClick() {
window.location.href =
"lightrouter://test.flyjingfish.com/user/DetailActivity?age=10&name=hahahaha&aChar=a&user={\"id\":\"1111\",\"name\":\"哈哈😄\"}"
}
</script>
- 定义拦截器
class UserIntercept : RouterIntercept {
//跳转页面时会先进入这里
override fun onIntercept(point: InterceptPoint) {
Log.e("onIntercept","--UserIntercept--${point.path},params = ${point.paramsMap},byPath = ${point.byPath}")
//调用下边这句才会进入下一个拦截器或跳转页面,支持异步获取网络数据后再调用
point.proceed()
}
//返回序号,存在多个拦截器时会按照这个顺序依次进入拦截器
override fun order(): Int {
return 2
}
}
- 初始化拦截器
object CollectApp {
private val allRouterIntercept = mutableSetOf<RouterIntercept>()
/**
* 这一步才可以收集到所有的拦截器
*/
@AndroidAopCollectMethod
@JvmStatic
fun collectIntercept(sub: RouterIntercept){
Log.e("CollectIntercept","collectIntercept=$sub")
allRouterIntercept.add(sub)
}
fun onCreate(application: Application){
Log.e("CollectIntercept","getAllRouterIntercept-size=${allRouterIntercept.size}")
//设置全部的拦截器让其起作用
RouterInterceptManager.addAllIntercept(allRouterIntercept)
}
}
//初始化
class MyApp : Application() {
override fun onCreate() {
super.onCreate()
//一键初始化所有需要的信息
CollectApp.onCreate(this)
}
}
- 动态增加拦截器
上边的初始化默认用的是 AndroidAOP 的收集直接继承类(并且不是抽象类的),我们想要动态添加拦截器,就不可直接实现
RouterIntercept
接口了,需要在中间加一层,避开这个规则,代码如下:
//定一个中间的 interface 类(或 abstract class),不可用 class,
//否则这个类会被认为是固有拦截器(即使你动态的创建对象也一样的)
interface IgnoreIntercept:RouterIntercept {
}
//动态添加就用 IgnoreIntercept
val intercept = object :IgnoreIntercept{
override fun onIntercept(point: InterceptPoint) {
point.proceed()
}
override fun order(): Int {
return 2
}
}
//动态添加拦截器
RouterInterceptManager.addIntercept(intercept)
//动态删除拦截器
RouterInterceptManager.removeIntercept(intercept)
// 自己定义一个 IApplication
interface IApplication {
fun onCreate(application: Application)
}
// 在各自 module 下实现这个接口
class UserApplication:IApplication {
override fun onCreate(application: Application) {
Log.e("IApplication",""+UserApplication::class.java.name)
}
}
object CollectApp {
private val allIApplication = mutableSetOf<IApplication>()
/**
* 收集所有的 module 的 IApplication 类
*/
@AndroidAopCollectMethod
@JvmStatic
fun collectIApplication(sub: IApplication){
Log.e("CollectIntercept","collectIApplication=$sub")
allIApplication.add(sub)
}
fun onCreate(application: Application){
Log.e("CollectIntercept","getAllRouterIntercept-size=${allRouterIntercept.size}")
//循环调用各个 module 的 IApplication.onCreate
allIApplication.forEach {
it.onCreate(application)
}
}
}
//初始化
class MyApp : Application() {
override fun onCreate() {
super.onCreate()
//一键初始化所有需要的信息
CollectApp.onCreate(this)
}
}
- 定义接口
@ExposeInterface
interface LoginHelper {
fun getLogin():Login
}
- 定义实现类
@ImplementClass(LoginHelper::class)
class LoginHelperImpl:LoginHelper {
override fun getLogin(): Login {
return Login("username:1111")
}
}
- 使用
val loginHelper = ImplementClassUtils.getSingleInstance<LoginHelper>(LoginHelper::class)
val login = loginHelper?.getLogin()
按照其他多数路由框架的设计思路,
LoginHelper
是放在 公共 module 的,LoginHelperImpl
则是放在提供服务的 module ,但 ModuleCommunication,可以将LoginHelper
也放在提供服务的 module 下,有兴趣可以去看看
- 不用
反射
获取到服务
object CollectApp {
/**
* 收集所有的 module 的 @ExposeInterface 共享实现类
*/
@AndroidAopCollectMethod
@JvmStatic
fun collectBindClass(sub: BindClass<*>){
Log.e("CollectIntercept","collectBindClass=$sub")
ImplementClassUtils.addBindClass(sub)
}
fun onCreate(application: Application){
}
}
//初始化
class MyApp : Application() {
override fun onCreate() {
super.onCreate()
//一键初始化所有需要的信息
CollectApp.onCreate(this)
}
}
- 定义降级策略(支持多个)
class UserLost : RouterLost{
//跳转页面时找不到页面会进入这里
override fun onLost(lostPoint: LostPoint) {
Log.e("onLost","--UserLost--")
//调用下边这句才会进入下一个降级策略类,不调用表示消耗掉此次事件,支持异步获取网络数据后再调用
lostPoint.proceed()
}
//返回序号,存在多个降级策略类时会按照这个顺序依次进入
override fun order(): Int {
return 2
}
}
- 初始化降级策略
object CollectApp {
private val allRouterLost = mutableSetOf<RouterLost>()
/**
* 这一步才可以收集到所有的降级处理器
*/
@AndroidAopCollectMethod
@JvmStatic
fun collectRouterLost(sub: RouterLost){
Log.e("CollectIntercept","collectRouterLost=$sub")
allRouterLost.add(sub)
}
fun onCreate(application: Application){
Log.e("CollectIntercept","getAllRouterIntercept-size=${allRouterIntercept.size}")
//设置全部降级策略类
RouterLostManager.addAllRouterLost(allRouterLost)
}
}
//初始化
class MyApp : Application() {
override fun onCreate() {
super.onCreate()
//一键初始化所有需要的信息
CollectApp.onCreate(this)
}
}
你可以看到上边所有功能都写了要初始化,其实这些初始化都可以放在一个类里边去,这样便于集中管理。另外说明一点,这样写完之后,之后你再加任何
@Route
、拦截器
、伪Application
、非反射服务
、降级策略
,都是自动生效的
object CollectApp {
private val allRouterIntercept = mutableSetOf<RouterIntercept>()
private val allIApplication = mutableSetOf<IApplication>()
private val allRouteClazz = mutableSetOf<BaseRouterClass>()
private val allRouterLost = mutableSetOf<RouterLost>()
/**
* 这一步才可以收集到所有的拦截器
*/
@AndroidAopCollectMethod
@JvmStatic
fun collectIntercept(sub: RouterIntercept){
Log.e("CollectIntercept","collectIntercept=$sub")
allRouterIntercept.add(sub)
}
/**
* 这一步才可以收集到所有的路由路径信息
*/
@AndroidAopCollectMethod
@JvmStatic
fun collectRouterClass(sub: BaseRouterClass){
Log.e("CollectIntercept","collectRouterClass=$sub")
allRouteClazz.add(sub)
}
/**
* 收集所有的 module 的 IApplication 类
*/
@AndroidAopCollectMethod
@JvmStatic
fun collectIApplication(sub: IApplication){
Log.e("CollectIntercept","collectIApplication=$sub")
allIApplication.add(sub)
}
/**
* 设置此项是为了 ImplementClassUtils 不用反射
*/
@AndroidAopCollectMethod
@JvmStatic
fun collectBindClass(sub: BindClass<*>){
Log.e("CollectIntercept","collectBindClass=$sub")
ImplementClassUtils.addBindClass(sub)
}
/**
* 这一步才可以收集到所有的降级处理器
*/
@AndroidAopCollectMethod
@JvmStatic
fun collectRouterLost(sub: RouterLost){
Log.e("CollectIntercept","collectRouterLost=$sub")
allRouterLost.add(sub)
}
fun onCreate(application: Application){
Log.e("CollectIntercept","getAllRouterIntercept-size=${allRouterIntercept.size}")
//设置全部的拦截器让其起作用
RouterInterceptManager.addAllIntercept(allRouterIntercept)
//设置全部路由路径信息,这样ModuleRoute才可以起作用
ModuleRoute.autoAddAllRouteClass(allRouteClazz)
//循环调用各个 module 的 IApplication.onCreate
allIApplication.forEach {
it.onCreate(application)
}
//设置这一项跳转页面可以不需要上下文
ModuleRoute.setApplication(application)
//设置全部降级策略类
RouterLostManager.addAllRouterLost(allRouterLost)
}
}
//初始化
class MyApp : Application() {
override fun onCreate() {
super.onCreate()
//一键初始化所有需要的信息
CollectApp.onCreate(this)
}
}
混淆规则遵循以下两个库的混淆规则: