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

Flutter提交评论按钮点击后应用崩溃问题求助

Flutter提交评论按钮点击后应用崩溃

我正在开发Flutter应用的提交评论功能,流程是点击“Add review”按钮打开底部弹窗,用户可以选择1-5星评分并输入评论内容,但点击“Submit Review”按钮后应用直接崩溃。

相关代码如下:

void _showReviewSheet(BuildContext context) {
    int selectedRating = 0;
    final reviewController = TextEditingController();

    showModalBottomSheet(
      context: context,
      isScrollControlled: true,
      backgroundColor: Colors.white,
      shape: const RoundedRectangleBorder(
        borderRadius: BorderRadius.vertical(top: Radius.circular(20)),
      ),
      builder: (context) => StatefulBuilder(
        builder: (context, setState) => Padding(
          padding: EdgeInsets.only(
            bottom: MediaQuery.of(context).viewInsets.bottom,
            left: 16,
            right: 16,
            top: 16,
          ),
          child: Column(
            mainAxisSize: MainAxisSize.min,
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              Row(
                mainAxisAlignment: MainAxisAlignment.spaceBetween,
                children: [
                  const Text(
                    'Write a Review',
                    style: TextStyle(
                      fontSize: 20,
                      fontWeight: FontWeight.bold,
                    ),
                  ),
                  IconButton(
                    icon: const Icon(Icons.close),
                    onPressed: () => Navigator.pop(context),
                  ),
                ],
              ),
              const SizedBox(height: 16),
              Row(
                mainAxisAlignment: MainAxisAlignment.center,
                children: List.generate(5, (index) {
                  return IconButton(
                    icon: Icon(
                      index < selectedRating ? Icons.star : Icons.star_border,
                      color: Colors.orange,
                      size: 32,
                    ),
                    onPressed: () {
                      setState(() {
                        selectedRating = index + 1;
                      });
                    },
                  );
                }),
              ),
              const SizedBox(height: 16),
              TextField(
                controller: reviewController,
                maxLines: 3,
                decoration: InputDecoration(
                  hintText: 'Share your experience...',
                  border: OutlineInputBorder(
                    borderRadius: BorderRadius.circular(12),
                  ),
                  filled: true,
                  fillColor: Colors.grey[100],
                ),
              ),
              const SizedBox(height: 16),
              SizedBox(
                width: double.infinity,
                child: ElevatedButton(
                  onPressed: () async {
                    if (selectedRating == 0) {
                      ScaffoldMessenger.of(context).showSnackBar(
                        const SnackBar(content: Text('Please select a rating')),
                      );
                      return;
                    }

                    try {
                      print('Attempting to submit review...'); // Debug print

                      // Create the review data
                      final reviewData = {
                        'userId': userId,
                        'rating': selectedRating,
                        'comment': reviewController.text.trim(),
                        'timestamp': FieldValue.serverTimestamp(),
                      };

                      print('Review data: $reviewData'); // Debug print

                      // Get the current document
                      final docRef = FirebaseFirestore.instance
                          .collection('programs')
                          .doc(workoutId);

                      // Update the document using arrayUnion
                      await docRef.update({
                        'reviews': FieldValue.arrayUnion([reviewData])
                      });

                      print('Review submitted successfully'); // Debug print

                      // Close bottom sheet and show success message
                      if (context.mounted) {
                        Navigator.pop(context);
                        ScaffoldMessenger.of(context).showSnackBar(
                          const SnackBar(
                            content: Text('Review added successfully'),
                            backgroundColor: Colors.green,
                          ),
                        );
                      }
                    } catch (e) {
                      print('Error adding review: $e'); // Debug print
                      if (context.mounted) {
                        ScaffoldMessenger.of(context).showSnackBar(
                          SnackBar(
                            content: Text('Error adding review: $e'),
                            backgroundColor: Colors.red,
                          ),
                        );
                      }
                    }
                  },
                  style: ElevatedButton.styleFrom(
                    backgroundColor: Colors.orange,
                    padding: const EdgeInsets.symmetric(vertical: 16),
                    shape: RoundedRectangleBorder(
                      borderRadius: BorderRadius.circular(12),
                    ),
                  ),
                  child: const Text(
                    'Submit Review',
                    style: TextStyle(
                      fontSize: 16,
                      fontWeight: FontWeight.bold,
                    ),
                  ),
                ),
              ),
              const SizedBox(height: 16),
            ],
          ),
        ),
      ),
    );
  }

问题排查与解决

1. 上下文失效风险

弹窗内的context属于弹窗路由,异步操作完成后可能已被释放。建议改用根导航器关闭弹窗,或提前通过全局Key管理SnackBar,避免依赖弹窗上下文:

// 全局定义
final scaffoldMessengerKey = GlobalKey<ScaffoldMessengerState>();

// 在MaterialApp中配置
MaterialApp(
  scaffoldMessengerKey: scaffoldMessengerKey,
  // ...其他配置
);

// 提交成功后使用
scaffoldMessengerKey.currentState?.showSnackBar(
  const SnackBar(content: Text('评论提交成功')),
);
Navigator.of(context, rootNavigator: true).pop();

2. Firestore数据类型不匹配

崩溃核心原因大概率是reviews字段类型与传入数据不兼容:

  • 确认Firestore中programs集合的reviews字段是数组类型,且数组内对象的字段类型与reviewData一致(比如userId为字符串、rating为数字)。
  • 若reviews字段不存在,arrayUnion会自动创建数组;但如果字段存在但非数组类型,会直接抛出错误导致崩溃。

3. 变量未初始化检查

确保userId和workoutId已正确赋值,避免空值传入Firestore:

if (userId == null || workoutId == null) {
  ScaffoldMessenger.of(context).showSnackBar(
    const SnackBar(content: Text('用户或项目信息未加载完成')),
  );
  return;
}

4. 控制器内存泄漏修复

弹窗内创建的reviewController需在弹窗关闭时销毁,避免内存泄漏:

showModalBottomSheet(
  // ...其他参数
  builder: (context) => StatefulBuilder(
    builder: (context, setState) {
      WidgetsBinding.instance.addPostFrameCallback((_) {
        ModalRoute.of(context)?.addScopedWillPopCallback(() async {
          reviewController.dispose();
          return true;
        });
      });
      // ...原有布局代码
    },
  ),
);

5. 查看具体错误信息

控制台打印的Error adding review: $e会显示崩溃的具体原因(如Firestore权限不足、字段类型错误等),这是最快定位问题的方式。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 18:32:08