LJ的Blog

学海无涯苦做舟

0%

Android中跨模块传递数据

一个小问题

最近碰到一个有趣的情况,在做一个功能时,考虑到从零开始开发需要花费大量的时间和精力,所以选用了一个有 UI 的库,并在这个库的基础之上进行二次开发。于是在项目中引入了这个库,当然,当时已经有大部分功能开发完成了,所以 UI 有一部分在 app 这个主模块中,而一部分则依赖这个库。Android Studio 中 app 模块是可以依赖其他引入项目的库的,而库则不可以依赖 app 模块,那这就引发了一个问题:主要功能已经在 app 中开发完毕,比如用户信息模块,而这个 UI 库的一些 UI 更新和功能也需要当前的用户信息,这该怎么办呢?

仔细分析

首先弄清楚这个问题的本质,这个问题的本质上是模块依赖引发的问题,仅仅是库依赖不了 app 模块的问题,所以不要用过于复杂的方法去解决,比如通过文件读写(sp文件)或者 socket 之类的。在刚开始时我第一个想到的是用 EventBus,但是想了想觉得不合适。EventBus 是一个事件发布订阅的模型,你可以想象一下这个情况:

  • UI 库发送请求用户信息事件
  • app 模块订阅了 请求用户信息事件
  • app 模块在收到请求后,发送 返回用户信息事件
  • UI 库订阅了 返回用户信息事件 ,收到事件后解析获取相应的信息

本来一来一回的操作,竟然需要四步操作,实在是有点麻烦,那有没有简单一些的方法呢?肯定是有的(废话,不然我也不会写这篇文章),再来分析一下该怎么实现:

  • app 中引入了 UI 库,所以 app 中可以直接使用 UI 库中的代码
  • 可以在 UI 库中定义一个用户接口,定义一系列自己所需要的用户信息的方法
  • 在 app 模块中实现这个接口,这很容易理解,app 可以直接使用 UI 库中的代码,而且 app 模块中也可以很轻易的访问到所需要的用户信息(毕竟原有的功能就是在 app 中开发的)
  • 做完上面几步,最后就是把 app 中的这个实现类注入到 UI 库中,这一步利用 Java 的多态来做到,这里放一下简单的代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
interface UserInterface {
fun getNickName(): String
}

object UserProxy {
lateinit var userImpl: UserInterface

fun injectUserImpl(userInterface: UserInterface) {
this.userImpl = userInterface
}

fun getNickName(): String {
return userImpl.getNickName()
}
}

在 UserProxy 中定义一个接口类型的属性,之后 app 调用这个注入方法,注入一个实现对象,整个流程就轻松愉快的完成了。

所有的实现代码(不包括视图代码 Kotlin 实现)

库的接口等代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
interface UserInterface {
fun getNickName(): String
}

object UserProxy {
lateinit var userImpl: UserInterface

fun injectUserImpl(userInterface: UserInterface) {
this.userImpl = userInterface
}

fun getNickName(): String {
return userImpl.getNickName()
}
}

app 中注入以及接口实现(简单实现。。。非生产代码)

1
2
3
4
5
6
7
8
9
10
11
12
class UserImpl : UserInterface {
override fun getNickName(): String {
return "xiasuhuei321"
}
}

class MyApplication : Application(){
override fun onCreate() {
super.onCreate()
UserProxy.injectUserImpl(UserImpl())
}
}

最后,稍微想了想,如果从刚开始就采用组件化来进行开发的话,也许就不会存在这个问题了,在组件化开发中,app 模块只是一个壳,其他的一个个模块既是单独可运行的 app 又是一个个库,只需要通过改变配置即可实现切换。不过这也是有空的时候再去折腾了,而且这种开发模式……暂时对我来说也没什么意义,项目也没大到那种程度,编译运行的速度也还可以,完全没到忍受不了的程度,而且我觉得这种模式可能更适合开发人员比较多的情况�