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

Android中获取到历史通话时长而非刚挂断通话时长的问题

解决通话挂断后获取最新通话时长的问题

嘿,我明白你遇到的麻烦了——刚挂断通话就去查时长,结果拿到的是上一次的,这确实挺闹心的。问题出在系统的通话记录(CallLog)并不是在通话挂断瞬间就立刻写入数据库的,你现在的代码是挂断后马上调用LastCall()去查询,这时候新的通话记录还没被系统保存下来,自然拿到的是之前的那条。

接下来给你几个可行的解决方案,按可靠性排序:

方案1:使用ContentObserver监听CallLog变化(推荐)

这是最靠谱的方式,我们可以注册一个内容观察者,当系统更新CallLog的时候,再去查询最新的通话时长,这样能保证拿到的是刚挂断的那条记录。

修改步骤:

  1. 定义一个ContentObserver子类:
private class CallLogObserver extends ContentObserver {
    public CallLogObserver(Handler handler) {
        super(handler);
    }

    @Override
    public void onChange(boolean selfChange) {
        super.onChange(selfChange);
        // 当CallLog更新时,查询最新通话时长
        String dura = LastCall();
        // 这里处理你的业务逻辑,比如更新白名单限制
        WhitelistDAO whiteListDao1 = new WhitelistDAO(context);
        if (dura.equals("0")) {
            int dbTime = Integer.parseInt(whiteListDao1.getLimit(finalNumber));
            whiteListDao1.updateLimit(String.valueOf(dbTime), finalNumber);
        } else {
            whiteListDao1.updateLimit("0", finalNumber);
        }
    }
}
  1. 在你的Activity或Service里注册和注销观察者:
private CallLogObserver callLogObserver;
private Handler handler = new Handler();

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    // 注册观察者
    callLogObserver = new CallLogObserver(handler);
    getContentResolver().registerContentObserver(
            CallLog.Calls.CONTENT_URI,
            true,
            callLogObserver
    );
}

@Override
protected void onDestroy() {
    super.onDestroy();
    // 注销观察者,避免内存泄漏
    if (callLogObserver != null) {
        getContentResolver().unregisterContentObserver(callLogObserver);
    }
}
  1. 修改你的disconnect()方法,去掉里面直接查询时长的逻辑,只保留挂断通话的部分:
public void disconnect(){ 
    disconnectPhoneItelephony(context); 
    calldisconnected(); 
    // 这里不再直接查询时长,等待CallLogObserver触发后处理
}

方案2:延迟查询(简单但不够可靠)

如果暂时不想用观察者,也可以给查询加个短延迟,让系统有时间写入CallLog。比如用Handler.postDelayed():

public void disconnect(){ 
    disconnectPhoneItelephony(context); 
    calldisconnected(); 
    
    new Handler().postDelayed(new Runnable() {
        @Override
        public void run() {
            WhitelistDAO whiteListDao1 = new WhitelistDAO(context);
            String dura = LastCall(); 
            if (dura.equals("0")) { 
                int dbTime = Integer.parseInt(whiteListDao1.getLimit(finalNumber)); 
                whiteListDao1.updateLimit(String.valueOf(dbTime), finalNumber); 
            } else { 
                whiteListDao1.updateLimit("0", finalNumber); 
            }
        }
    }, 500); // 延迟500毫秒,可根据设备调整
}

⚠️ 注意:这个方法的缺点是不同设备的系统写入速度不一样,延迟时间设短了可能还是拿不到最新记录,设长了用户会有明显等待感,所以优先推荐方案1。

额外检查点

  • 确保你已经动态申请了READ_CALL_LOG权限,并且用户已经授权,虽然你的代码里有检查,但要确认权限申请流程是正确的(比如在Activity里请求权限,处理onRequestPermissionsResult)。
  • 你的LastCall()方法里,查询时排序用的是android.provider.CallLog.Calls.DATE+ " DESC limit 1;",这个是对的,能拿到最新的通话记录,只要时机对就没问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 03:59:16