在Activity、Application类中使用companion object是否是合理的实现方案?
现有实现的弊端
1. Intent键分散定义的弊端
- 维护成本高:键分散在不同组件的伴生对象中,新增、修改、查找对应键都需要遍历多个类,团队协作时很容易出现不同人重复定义相似键的问题
- 出错风险高:如果不同组件意外定义了同名的extra键,传值时会出现数据覆盖、取值错误的问题,这类问题很难排查
- 耦合度高:Adapter、无关Activity直接依赖特定Activity的伴生对象,不符合最少知道原则,后续重构目标Activity时会牵扯大量外部调用的修改
2. Application静态存储Context的弊端
- 存在空指针风险:你把
appContext定义为可空变量,如果在updateContext执行前就访问该变量,会直接触发NPE - 封装性被破坏:可读写的全局静态变量允许任意位置修改
appContext的值,很容易出现不可预期的运行错误 - 不利于测试:静态存储的Context无法方便地做单元测试,mock成本很高
优化方案
1. Intent键优化方案
方案A:统一收拢常量
新建单独的常量文件管理全局通用的键,避免分散在各个类中:
// 新建IntentKeys.kt顶层文件 const val SEND_MY_DATA = "sendta" const val SEND_MY_DATA_1 = "sendta1" const val SEND_MY_DATA_2 = "sendta2"
方案B(更推荐):封装跳转方法隐藏键细节
把键定义为目标Activity的私有常量,对外只暴露跳转方法,外部不需要感知键的存在:
class TargetActivity : AppCompatActivity() { companion object { // 对外暴露统一跳转方法,参数明确,不需要外部传Intent或者写键 fun start(context: Context, data: String, data1: Int, data2: Boolean) { val intent = Intent(context, TargetActivity::class.java).apply { putExtra(SEND_MY_DATA, data) putExtra(SEND_MY_DATA_1, data1) putExtra(SEND_MY_DATA_2, data2) } context.startActivity(intent) } // 键设为私有,完全不对外暴露 private const val SEND_MY_DATA = "sendta" private const val SEND_MY_DATA_1 = "sendta1" private const val SEND_MY_DATA_2 = "sendta2" } // 内部取值也用私有常量,避免写错 private val getData by lazy { intent.getStringExtra(SEND_MY_DATA).orEmpty() } }
调用时直接写TargetActivity.start(this, "test", 1, true)即可,编译期就能校验参数类型和数量,完全避免写错键的问题。
2. Application Context优化方案
修改为只读的全局Context,保证只会初始化一次,不允许外部修改:
class MyApp : Application() { companion object { // 加private set禁止外部修改,lateinit保证非空 lateinit var appContext: Context private set } override fun onCreate() { super.onCreate() appContext = applicationContext } }
Application的onCreate是应用启动的第一个执行流程,不会出现未初始化就访问的情况,也彻底避免了空指针和被意外修改的问题。如果项目接入了Hilt等依赖注入框架,更推荐通过注入的方式获取Context,进一步降低耦合。
内容的提问来源于stack exchange,提问作者c-an
相关产品推荐
相关产品推荐

