You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android Kotlin:Service无法调用MainActivity的sendSOS方法问题

SOS应用摇晃触发功能故障排查与修复

问题核心

SensorService检测到摇晃后调用MainActivity的sendSOS()方法时抛出空指针异常,根源是手动实例化MainActivity对象——Activity必须由Android系统初始化生命周期,直接new MainActivity()会导致Context为空,进而调用LocationServices.getFusedLocationProviderClient(this)时崩溃。

报错信息

java.lang.NullPointerException: Attempt to invoke virtual method 'android.content.Context android.content.Context.getApplicationContext()' on a null object reference
                                    at android.content.ContextWrapper.getApplicationContext(ContextWrapper.java:135)
                                    at com.google.android.gms.common.api.GoogleApi.<init>(com.google.android.gms:play-services-base@@18.1.0:7)
                                    at com.google.android.gms.common.api.GoogleApi.<init>(com.google.android.gms:play-services-base@@18.1.0:1)
                                    at com.google.android.gms.internal.location.zzbp.<init>(com.google.android.gms:play-services-location@@21.0.1:1)
                                    at com.google.android.gms.location.LocationServices.getFusedLocationProviderClient(com.google.android.gms:play-services-location@@21.0.1:1)
                                    at com.chrizlove.helpapp.MainActivity.sendSOS(MainActivity.kt:142)
                                    at com.chrizlove.helpapp.SensorService$onCreate$1.onShake(SensorService.kt:67)
                                    at com.chrizlove.helpapp.ShakeDetector.onSensorChanged(ShakeDetector.kt:51)

错误代码片段(SensorService调用部分)

override fun onShake(count: Int) {
    if (count == 3) {
        vibrate()
        // 错误:手动创建Activity实例,未经过系统初始化
        val mActivity = MainActivity()
        mActivity.sendSOS(applicationContext)
        Toast.makeText(applicationContext,"Shaken", Toast.LENGTH_SHORT).show()
    }
}

修复方案

采用**广播(BroadcastReceiver)**实现Service与Activity的通信,这是Android组件间通信的标准方式:

步骤1:在MainActivity中注册广播接收器

class MainActivity : AppCompatActivity() {
    private val sosBroadcastReceiver = object : BroadcastReceiver() {
        override fun onReceive(context: Context?, intent: Intent?) {
            if (intent?.action == "com.chrizlove.helpapp.SEND_SOS") {
                // 调用当前已初始化的Activity实例的sendSOS方法
                sendSOS(applicationContext)
            }
        }
    }

    override fun onResume() {
        super.onResume()
        // 注册广播过滤器
        val filter = IntentFilter("com.chrizlove.helpapp.SEND_SOS")
        registerReceiver(sosBroadcastReceiver, filter)
    }

    override fun onPause() {
        super.onPause()
        // 注销广播,避免内存泄漏
        unregisterReceiver(sosBroadcastReceiver)
    }

    // 保留原有sendSOS及相关方法
    public fun sendSOS(context: Context) {
        fusedLocationProviderClient=LocationServices.getFusedLocationProviderClient(this)
        getCurrentLocationAndSendSMS(context)
    }

    // ... 其他原有方法不变
}

步骤2:修改SensorService,发送广播触发SOS

override fun onShake(count: Int) {
    if (count == 3) {
        vibrate()
        // 发送广播替代手动创建Activity实例
        val intent = Intent("com.chrizlove.helpapp.SEND_SOS")
        sendBroadcast(intent)
        Toast.makeText(applicationContext,"Shaken", Toast.LENGTH_SHORT).show()
    }
}

额外优化建议

  1. 后台兼容处理:若需要App在后台也能响应SOS,建议将位置获取、短信发送逻辑迁移至Service中,避免依赖Activity生命周期。
  2. 空安全优化:contactViewModel.contacts.value!!存在空指针风险,改为contactViewModel.contacts.value?.let { contacts -> ... }更安全。
  3. 前台Service保障:确保SensorService始终以前台Service运行,避免被系统回收影响紧急功能响应。

内容的提问来源于stack exchange,提问作者Chrizlove

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.20 09:28:08