
在 Android 12(SDK 31)及以上版本中,TelephonyManager.listen() 已被弃用,需改用 registerTelephonyCallback() 配合 TelephonyCallback.CallStateListener 实时监听通话状态(如拨出、接通、挂断),本文详解安全、合规的注册与回调实现。
在 android 12(sdk 31)及以上版本中,`telephonymanager.listen()` 已被弃用,需改用 `registertelephonycallback()` 配合 `telephonycallback.callstatelistener` 实时监听通话状态(如拨出、接通、挂断),本文详解安全、合规的注册与回调实现。
自 Android 12(API level 31)起,系统出于隐私与后台限制考量,彻底废弃了传统的 TelephonyManager.listen() 方法。若你的应用仍需感知用户发起或结束通话(例如:自动关闭语音通道、更新 UI 状态、触发后续业务逻辑),必须迁移到基于 TelephonyCallback 的新机制。该方案不仅更轻量、线程安全,还天然适配主线程执行器(MainExecutor),避免手动处理 Handler 或 Looper。
✅ 正确实现步骤
继承 TelephonyCallback 并实现 CallStateListener 接口
注意:TelephonyCallback 是抽象基类,不可直接实例化;必须子类化并重写所需监听方法(如 onCallStateChanged)。在合适生命周期内注册/注销回调
建议在 Activity.onResume() 或 Service.onStartCommand() 中注册,在 onPause() 或 onDestroy() 中调用 unregisterTelephonyCallback() —— 未及时注销将导致内存泄漏与资源占用。使用 getMainExecutor() 保证回调在主线程执行
所有 TelephonyCallback 方法均在指定 Executor 上调用,主线程回调可直接更新 UI,无需额外切线程。
以下是完整、可直接集成的示例代码:
public class CallStateMonitor extends TelephonyCallback implements TelephonyCallback.CallStateListener {
private static final String TAG = "CallStateMonitor";
private final Context context;
public CallStateMonitor(Context context) {
this.context = context.getApplicationContext(); // 使用 Application Context 避免 Activity 泄漏
}
@Override
public void onCallStateChanged(@TelephonyManager.CallState int state) {
switch (state) {
case TelephonyManager.CALL_STATE_IDLE:
Log.i(TAG, "通话已结束或无活跃通话");
// ✅ 此处处理“挂断”逻辑:如停止录音、释放媒体资源、跳转页面等
break;
case TelephonyManager.CALL_STATE_OFFHOOK:
Log.i(TAG, "通话已接通(正在通话中)");
// ⚠️ 注意:CALL_STATE_OFFHOOK 包含拨出接通、呼入接听两种场景
break;
case TelephonyManager.CALL_STATE_RINGING:
Log.i(TAG, "有来电振铃中");
// 可选:响应来电事件(需 READ_PHONE_STATE 权限)
break;
default:
Log.w(TAG, "未知通话状态: " + state);
}
}
}在 Activity 或 Service 中注册与销毁:
private CallStateMonitor callStateMonitor;
@Override
protected void onResume() {
super.onResume();
TelephonyManager tm = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
if (tm != null) {
callStateMonitor = new CallStateMonitor(this);
tm.registerTelephonyCallback(getMainExecutor(), callStateMonitor);
}
}
@Override
protected void onPause() {
super.onPause();
if (callStateMonitor != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
TelephonyManager tm = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
if (tm != null) {
tm.unregisterTelephonyCallback(callStateMonitor);
}
callStateMonitor = null;
}
}⚠️ 关键注意事项
权限要求:监听 CALL_STATE_RINGING 和 CALL_STATE_OFFHOOK 需要 READ_PHONE_STATE(危险权限,Android 10+ 还需声明 android.permission.READ_CALL_LOG 或满足特殊豁免条件);但 CALL_STATE_IDLE 通常无需运行时权限(仅需 android.permission.READ_PHONE_STATE 在 AndroidManifest.xml 中声明)。请严格遵循 Android 电话权限指南。
作用域限制:registerTelephonyCallback() 仅在应用处于前台或前台服务运行时可靠触发。后台应用受 Android 9+ 后台执行限制影响,无法持续监听通话状态 —— 这是系统级设计,不可绕过。
-
状态语义说明:
- CALL_STATE_IDLE:表示当前无任何通话活动(包括刚挂断后),是检测“通话结束”的唯一可靠信号;
- CALL_STATE_OFFHOOK:表示至少有一路通话处于已接通状态(无论主叫/被叫),不等于“开始通话”瞬间,可能存在延迟;
- CALL_STATE_RINGING:仅对呼入有效,且需权限支持。
兼容性提示:该 API 自 Android 11(API 30)引入,但 CALL_STATE_IDLE 的稳定性在 SDK 31(Android 12)后显著增强,推荐以 Build.VERSION.SDK_INT >= Build.VERSION_CODES.S 为最低目标。
✅ 总结
迁移到 TelephonyCallback 不仅是适配新 SDK 的强制要求,更是提升应用健壮性与用户体验的关键一步。通过合理封装监听器、严格管理生命周期、理解各状态语义,并结合权限与后台限制的客观约束,你可以在符合平台规范的前提下,精准捕获通话生命周期关键节点。务必测试真机场景(模拟器不支持真实通话状态),并在 targetSdkVersion ≥ 31 的 build 下全面验证行为一致性。










