Flutter中Firebase Storage上传状态获取的最新方法求助
Firebase Storage 上传状态获取问题解决(Flutter)
我尝试获取Firebase Storage文件的上传状态,但原代码中使用task.isComplete、task.isInProgress等属性时出现编译错误,提示属性不存在。原因是Firebase Storage的Flutter SDK更新后,上传任务的API发生了变更,以下是适配最新版本的解决方案。
原代码
Stateful类中的上传逻辑
uploadToFirebase() { String fileName = _path!.split('/').last; String filePath = _path!; upload(fileName, filePath); } upload(fileName, filePath) { FileType _pickType = FileType.custom; _extension = fileName.toString().split('.').last; Reference storageRef = FirebaseStorage.instance.ref().child(fileName); final UploadTask uploadTask = storageRef.putFile( File(filePath), SettableMetadata( contentType: '$_pickType/$_extension', ), ); setState(() { _tasks.add(uploadTask); }); } @override Widget build(BuildContext context) { final List<Widget> children = <Widget>[]; _tasks.forEach((UploadTask task) { final Widget tile = UploadTaskListTile( task: task, onDismissed: () => setState(() => _tasks.remove(task)), onDownload: () => downloadFile(task.snapshot.ref), ); children.add(tile); }); return Container(); }
UploadTaskListTile组件
class UploadTaskListTile extends StatelessWidget { const UploadTaskListTile( {Key? key, this.task, this.onDismissed, this.onDownload}) : super(key: key); final UploadTask? task; final VoidCallback? onDismissed; final VoidCallback? onDownload; String get status { String result; if (task!.isComplete) { if (task.isSuccessful) { result = 'Complete'; } else if (task.isCanceled) { result = 'Canceled'; } else { result = 'Failed ERROR: ${task.lastSnapshot.error}'; } } else if (task.isInProgress) { result = 'Uploading'; } else if (task.isPaused) { result = 'Paused'; } return result; } String _bytesTransferred(StorageTaskSnapshot snapshot) { return '${snapshot.bytesTransferred}/${snapshot.totalByteCount}'; } @override Widget build(BuildContext context) { return StreamBuilder<StorageTaskEvent>( stream: task.events, builder: (BuildContext context, AsyncSnapshot<StorageTaskEvent> asyncSnapshot) { Widget subtitle; if (asyncSnapshot.hasData) { final StorageTaskEvent event = asyncSnapshot.data; final StorageTaskSnapshot snapshot = event.snapshot; subtitle = Text('$status: ${_bytesTransferred(snapshot)} bytes sent'); } else { subtitle = const Text('Starting...'); } return Dismissible( key: Key(task.hashCode.toString()), onDismissed: (_) => onDismissed(), child: ListTile( title: Text('Upload Task #${task.hashCode}'), subtitle: subtitle, trailing: Row( mainAxisSize: MainAxisSize.min, children: <Widget>[ Offstage( offstage: !task.isInProgress, child: IconButton( icon: const Icon(Icons.pause), onPressed: () => task.pause(), ), ), Offstage( offstage: !task.isPaused, child: IconButton( icon: const Icon(Icons.file_upload), onPressed: () => task.resume(), ), ), Offstage( offstage: task.isComplete, child: IconButton( icon: const Icon(Icons.cancel), onPressed: () => task.cancel(), ), ), Offstage( offstage: !(task.isComplete && task.isSuccessful), child: IconButton( icon: const Icon(Icons.file_download), onPressed: onDownload, ), ), ], ), ), ); }, ); }
解决方案(适配Firebase Storage最新SDK)
Firebase Storage Flutter SDK更新后,UploadTask的API做了简化,原有的isComplete、isInProgress等属性被移除,改为通过UploadTaskSnapshot.state(枚举类型TaskState)来判断上传状态,同时监听上传进度的Stream也从events改为snapshotChanges()。
修改后的UploadTaskListTile组件
class UploadTaskListTile extends StatelessWidget { const UploadTaskListTile({ Key? key, this.task, this.onDismissed, this.onDownload, }) : super(key: key); final UploadTask? task; final VoidCallback? onDismissed; final VoidCallback? onDownload; String get status { if (task == null) return 'Unknown'; final snapshot = task!.snapshot; switch (snapshot.state) { case TaskState.success: return 'Complete'; case TaskState.canceled: return 'Canceled'; case TaskState.error: return 'Failed ERROR: ${snapshot.error}'; case TaskState.running: return 'Uploading'; case TaskState.paused: return 'Paused'; } } String _bytesTransferred(UploadTaskSnapshot snapshot) { return '${snapshot.bytesTransferred}/${snapshot.totalBytes}'; } @override Widget build(BuildContext context) { return StreamBuilder<UploadTaskSnapshot>( stream: task?.snapshotChanges(), builder: (context, asyncSnapshot) { Widget subtitle; if (asyncSnapshot.hasData) { final snapshot = asyncSnapshot.data!; subtitle = Text('$status: ${_bytesTransferred(snapshot)} bytes sent'); } else { subtitle = const Text('Starting...'); } final isRunning = task?.snapshot.state == TaskState.running; final isPaused = task?.snapshot.state == TaskState.paused; final isComplete = task?.snapshot.state == TaskState.success; final isCanceledOrError = task?.snapshot.state == TaskState.canceled || task?.snapshot.state == TaskState.error; return Dismissible( key: Key(task.hashCode.toString()), onDismissed: (_) => onDismissed?.call(), child: ListTile( title: Text('Upload Task #${task.hashCode}'), subtitle: subtitle, trailing: Row( mainAxisSize: MainAxisSize.min, children: <Widget>[ Offstage( offstage: !isRunning, child: IconButton( icon: const Icon(Icons.pause), onPressed: task?.pause, ), ), Offstage( offstage: !isPaused, child: IconButton( icon: const Icon(Icons.file_upload), onPressed: task?.resume, ), ), Offstage( offstage: isComplete || isCanceledOrError, child: IconButton( icon: const Icon(Icons.cancel), onPressed: task?.cancel, ), ), Offstage( offstage: !isComplete, child: IconButton( icon: const Icon(Icons.file_download), onPressed: onDownload, ), ), ], ), ), ); }, ); } }
关键修改点说明
- 替换监听流:将
StreamBuilder<StorageTaskEvent>改为StreamBuilder<UploadTaskSnapshot>,并使用task?.snapshotChanges()作为stream源。 - 状态判断:通过
task!.snapshot.state(TaskState枚举)判断上传状态,替代原有的isComplete、isInProgress等属性。 - 进度计算:
StorageTaskSnapshot改为UploadTaskSnapshot,对应的字节数属性从totalByteCount改为totalBytes。 - 空安全优化:增加空值判断,避免空指针异常,同时使用
?.call()简化回调调用。
内容的提问来源于stack exchange,提问作者Abhay Varma
相关产品推荐
相关产品推荐

