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

Flutter中使用call_log插件时如何在ListView组件内调用方法展示通话记录

实现Flutter通话记录展示到ListView的方案

你使用的call_log: ^3.0.3属于异步数据获取插件,不能直接在build方法中同步调用渲染,需要结合状态管理将获取到的通话记录存储后再渲染到ListView,具体实现步骤如下:

步骤1:配置基础权限

通话记录属于敏感权限,首先需要在安卓项目的android/app/src/main/AndroidManifest.xml的<manifest>标签下添加权限声明:

<uses-permission android:name="android.permission.READ_CALL_LOG" />

同时添加permission_handler依赖用于动态申请权限,在pubspec.yaml中添加:

dependencies:
  permission_handler: ^10.2.0

步骤2:完整实现代码

使用StatefulWidget存储通话记录数据,异步获取数据后通过setState刷新UI即可:

import 'package:call_log/call_log.dart';
import 'package:flutter/material.dart';
import 'package:permission_handler/permission_handler.dart';

class CallLogPage extends StatefulWidget {
  const CallLogPage({super.key});

  @override
  State<CallLogPage> createState() => _CallLogPageState();
}

class _CallLogPageState extends State<CallLogPage> {
  // 存储所有通话记录
  List<CallLogEntry> _callLogList = [];
  // 加载状态标记
  bool _isLoading = true;

  @override
  void initState() {
    super.initState();
    // 进入页面后先申请权限再获取通话记录
    _initCallLog();
  }

  Future<void> _initCallLog() async {
    // 动态申请通话记录读取权限
    PermissionStatus status = await Permission.phone.request();
    if (status.isGranted) {
      // 权限申请通过,获取通话记录
      Iterable<CallLogEntry> entries = await CallLog.get();
      setState(() {
        _callLogList = entries.toList();
        _isLoading = false;
      });
    } else {
      // 权限被拒绝的场景可自行补充逻辑
      setState(() {
        _isLoading = false;
      });
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text("通话记录")),
      body: _isLoading
          ? const Center(child: CircularProgressIndicator())
          : _callLogList.isEmpty
              ? const Center(child: Text("未查询到通话记录"))
              : ListView.builder(
                  itemCount: _callLogList.length,
                  itemBuilder: (context, index) {
                    CallLogEntry logItem = _callLogList[index];
                    return ListTile(
                      title: Text(logItem.name ?? "未知联系人"),
                      subtitle: Text("号码:${logItem.number ?? ''} | 通话时长:${logItem.duration ?? 0}秒"),
                      trailing: Text(_formatCallType(logItem.callType)),
                    );
                  },
                ),
    );
  }

  // 转换通话类型为可读文本
  String _formatCallType(CallType? type) {
    switch(type) {
      case CallType.incoming: return "呼入";
      case CallType.outgoing: return "呼出";
      case CallType.missed: return "未接";
      default: return "未知";
    }
  }
}

核心问题说明

你之前的写法问题在于没有将异步获取到的通话记录存储到State的变量中,也没有触发UI刷新,所以只能在控制台打印无法渲染到页面。所有需要展示到UI的异步数据都需要先存储到状态变量,再通过setState触发重新渲染。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.06 08:54:03