在 Android 開發中,監聽電話狀態變化以檢測未接來電是常見需求。本文對比 BroadcastReceiver(廣播接收器) 與 PhoneStateListener(電話狀態監聽器) 兩種主流方案,提供完整實現代碼、權限配置與優缺點分析。
電話三態:
CALL_STATE_IDLE:閒置(掛斷、無來電)CALL_STATE_RINGING:響鈴中CALL_STATE_OFFHOOK:通話中(接聽、撥出)未接來電判斷條件:上一狀態 == RINGING 且 當前狀態 == IDLE(響鈴後直接變閒置,未經 OFFHOOK)。
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
<receiver android:name=".receiver.PhoneStateReceiver">
<intent-filter>
<action android:name="android.intent.action.PHONE_STATE"/>
</intent-filter>
</receiver>
public class PhoneStateReceiver extends BroadcastReceiver {
// 靜態變量記錄上一狀態(進程存活期間有效)
private static int lastCallState = TelephonyManager.CALL_STATE_IDLE;
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (!TelephonyManager.ACTION_PHONE_STATE_CHANGED.equals(action)) return;
TelephonyManager tm = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
int currentState = tm.getCallState();
Log.d("PhoneState", "currentState=" + currentState);
// 核心判斷邏輯
if (lastCallState == TelephonyManager.CALL_STATE_RINGING
&& currentState == TelephonyManager.CALL_STATE_IDLE) {
Toast.makeText(context, "有未接來電", Toast.LENGTH_SHORT).show();
// TODO: 發送通知、記錄日誌、上報服務器等業務邏輯
}
lastCallState = currentState; // 更新狀態
}
}
TelephonyManager tm = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
// 傳入自定義 Listener,監聽 CALL_STATE 變化
tm.listen(new CallStateListener(this), PhoneStateListener.LISTEN_CALL_STATE);
public class CallStateListener extends PhoneStateListener {
private static int lastState = TelephonyManager.CALL_STATE_IDLE;
private Context context;
public CallStateListener(Context context) {
this.context = context;
}
@Override
public void onCallStateChanged(int state, String incomingNumber) {
super.onCallStateChanged(state, incomingNumber);
Log.d("CallState", "state=" + state + ", number=" + incomingNumber);
// 同樣的狀態機判斷
if (lastState == TelephonyManager.CALL_STATE_RINGING
&& state == TelephonyManager.CALL_STATE_IDLE) {
Toast.makeText(context, "CallStateListener 有未接來電", Toast.LENGTH_SHORT).show();
}
lastState = state;
}
}
incomingNumber 參數直接提供| 維度 | BroadcastReceiver | PhoneStateListener |
|---|---|---|
| 生命週期 | 進程級(靜態註冊) | 組件級(動態註冊) |
| 應用未啟動時 | ✅ 能接收 | ❌ 不能接收 |
| 獲取來電號碼 | 需額外從 Intent 解析 | ✅ 回調直接提供 |
| Android 8.0+ 適配 | 需動態註冊或豁免 | 無影響 |
| 適用場景 | 系統級監控、來電記錄、攔截 | 應用內顯示來電 UI、即時響應 |
原生 API 無法直接區分。常見變通方案:
CALL_STATE_OFFHOOK 後極短時間進入 IDLE 可能為拒接CallLog.Calls 類型字段(MISSED vs REJECTED),需權限READ_PHONE_STATE 屬於危險權限,需運行時申請READ_CALL_LOG選型原則:後台長駐監聽用 BroadcastReceiver(動態註冊),前台即時響應用 PhoneStateListener。實際項目常組合使用:BroadcastReceiver 負責喚醒應用,PhoneStateListener 負責前台交互。