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

Flutter中如何在本地通知展示API数据加载进度?

在通知栏展示数据加载进度的实现方案

Android 平台实现步骤

1. 创建通知渠道(Android 8.0+ 必需)

Android 8.0及以上版本要求所有通知归属到指定渠道,否则无法正常显示:

private fun createProgressNotificationChannel() {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        val channel = NotificationChannel(
            "PROGRESS_CHANNEL_ID",
            "数据加载进度",
            NotificationManager.IMPORTANCE_LOW // 低优先级,避免打扰用户
        ).apply {
            description = "实时展示数据加载进度"
        }
        val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
        notificationManager.createNotificationChannel(channel)
    }
}

2. 用前台服务执行加载并更新进度

耗时的API请求不能放在UI线程,通过前台服务后台执行任务,同时同步更新通知进度:

class DataLoadService : Service() {
    private val notificationManager by lazy { getSystemService(NOTIFICATION_SERVICE) as NotificationManager }
    private val serviceScope = CoroutineScope(Dispatchers.IO + Job())

    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
        // 初始化进度通知模板
        val notificationBuilder = NotificationCompat.Builder(this, "PROGRESS_CHANNEL_ID")
            .setContentTitle("正在更新数据")
            .setContentText("加载中...")
            .setSmallIcon(R.drawable.ic_download)
            .setPriority(NotificationCompat.PRIORITY_LOW)
            .setProgress(100, 0, false) // false为确定进度,true表示模糊加载状态

        // 启动前台服务,绑定通知
        startForeground(1, notificationBuilder.build())

        // 模拟API加载流程(替换为你的实际请求逻辑)
        serviceScope.launch {
            for (progress in 0..100 step 10) {
                delay(500) // 模拟加载耗时
                // 更新通知进度
                notificationBuilder.setProgress(100, progress, false)
                notificationBuilder.setContentText("已加载 ${progress}%")
                notificationManager.notify(1, notificationBuilder.build())
            }
            // 加载完成后更新通知状态
            notificationBuilder.setContentTitle("数据更新完成")
                .setContentText("所有数据已加载完毕")
                .setProgress(0, 0, false) // 隐藏进度条
            notificationManager.notify(1, notificationBuilder.build())
            stopForeground(STOP_FOREGROUND_REMOVE) // 停止前台服务
            stopSelf()
        }
        return START_NOT_STICKY
    }

    override fun onBind(intent: Intent?): IBinder? = null

    override fun onDestroy() {
        serviceScope.cancel()
        super.onDestroy()
    }
}

3. 点击按钮启动服务

在Activity的按钮点击事件中触发加载流程:

updateButton.setOnClickListener {
    val intent = Intent(this, DataLoadService::class.java)
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        startForegroundService(intent)
    } else {
        startService(intent)
    }
}

iOS 平台实现步骤

1. 请求通知权限

先向用户申请通知权限,否则无法展示通知:

import UserNotifications

func requestNotificationPermission() {
    UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound]) { granted, error in
        if let error = error {
            print("权限请求失败: \(error.localizedDescription)")
        }
    }
}

2. 创建并更新进度通知

通过后台任务执行加载,实时更新通知内容:

func startDataLoadWithProgress() {
    // 初始化通知内容
    let content = UNMutableNotificationContent()
    content.title = "正在更新数据"
    content.body = "加载中..."
    content.sound = .none

    // 添加初始通知
    let requestID = "DataLoadProgressRequest"
    let request = UNNotificationRequest(identifier: requestID, content: content, trigger: nil)
    UNUserNotificationCenter.current().add(request) { error in
        if let error = error {
            print("添加通知失败: \(error.localizedDescription)")
            return
        }

        // 模拟API加载流程(替换为你的实际请求逻辑)
        DispatchQueue.global().async {
            for progress in 0...100 step 10 {
                Thread.sleep(forTimeInterval: 0.5) // 模拟加载耗时
                DispatchQueue.main.async {
                    // 更新通知内容
                    let updatedContent = UNMutableNotificationContent()
                    updatedContent.title = "正在更新数据"
                    updatedContent.body = "已加载 \(progress)%"
                    updatedContent.sound = .none

                    // 用相同ID覆盖旧通知
                    let updatedRequest = UNNotificationRequest(identifier: requestID, content: updatedContent, trigger: nil)
                    UNUserNotificationCenter.current().add(updatedRequest) { _ in }
                }
            }

            // 加载完成后更新通知
            DispatchQueue.main.async {
                let finishContent = UNMutableNotificationContent()
                finishContent.title = "数据更新完成"
                finishContent.body = "所有数据已加载完毕"
                finishContent.sound = UNNotificationSound.default

                let finishRequest = UNNotificationRequest(identifier: requestID, content: finishContent, trigger: nil)
                UNUserNotificationCenter.current().add(finishRequest) { _ in }
            }
        }
    }
}

3. 按钮点击触发加载

绑定按钮点击事件,启动加载流程:

updateButton.addTarget(self, action: #selector(startLoad), for: .touchUpInside)

@objc func startLoad() {
    startDataLoadWithProgress()
}

通用注意事项

  • 避免UI阻塞:所有加载和进度更新逻辑必须放在后台线程,防止界面卡顿。
  • 真实进度计算:如果API支持分块/分段加载,可通过已加载字节数/总字节数、已加载页数/总页数计算真实进度;无明确总数据量时,可使用模糊进度模式(Android设置setProgress第三个参数为true,iOS可显示"加载中..."无具体百分比)。
  • 异常处理:加载失败时要及时更新通知,告知用户失败原因,可添加重试按钮跳转至重试逻辑。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.17 05:15:27