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

Flutter中Radio按钮变更的变量值无法传递至Database类

问题描述

我在Flutter项目中需要将Home类里存储Radio按钮组选中值的currentOption变量传递给Database类。目前的问题是:在Home类中切换Radio按钮时,currentOption通过setState能正常更新,在Home类内打印能得到正确的变更后的值;但在Database类中获取该变量时,打印出来的始终是Home类里的初始值,无法获取最新的变更值。


Home.dart(翻译注释后的代码)

import 'package:flutter/material.dart';
import 'package:watch_hub/services/auth.dart';
import 'package:watch_hub/services/database.dart';
import 'package:provider/provider.dart';
import 'package:watch_hub/screens/home/watch_list.dart';
import 'package:watch_hub/models/watch.dart';

List<dynamic> options = [0, 'Rolex', 'Longines'];

class Home extends StatefulWidget {
  Home({super.key});
  dynamic currentOption = options[0]; // 这是我想要传递至另一个类的变量
  @override
  State<Home> createState() => _HomeState();
}

class _HomeState extends State<Home> {
  final AuthService _auth = AuthService();

  @override
  Widget build(BuildContext context) {
    return StreamProvider<List<Watch>>.value(
      value: DatabaseService().watches,
      initialData: const [],
      child: Scaffold(
        backgroundColor: Colors.brown[50],
        drawer: Drawer(
          elevation: 20.0,
          child: Column(
            children: <Widget>[
              UserAccountsDrawerHeader(
                accountName: Text("Flutter"),
                accountEmail: null,
              ),
              // 切换这些单选按钮时currentOption的值会变更
              ListTile(
                title: const Text('无'),
                leading: Radio<dynamic>(
                  value: options[0],
                  groupValue: widget.currentOption,
                  onChanged: (value) {
                    setState(() {
                      widget.currentOption = value;
                      print("当前值为 ${widget.currentOption}");
                    });
                  },
                ),
              ),
              Divider(
                height: 0.1,
              ),
              ListTile(
                  title: const Text('Rolex'),
                  leading: Radio(
                    value: options[1],
                    groupValue: widget.currentOption,
                    onChanged: (value) {
                      setState(() {
                        widget.currentOption = value;
                        print("当前值为 ${widget.currentOption}");
                      });
                    },
                  )),
              ListTile(
                  title: const Text('Longines'),
                  leading: Radio(
                    value: options[2],
                    groupValue: widget.currentOption,
                    onChanged: (value) {
                      setState(() {
                        widget.currentOption = value;
                        print("当前值为 ${widget.currentOption}");
                      });
                    },
                  )),
              ListTile(
                title: Text("促销"),
                leading: Icon(Icons.local_offer),
              ),
            ],
          ),
        ),
        appBar: AppBar(
          title: Text("Watch Hub"),
          backgroundColor: Colors.brown[400],
          elevation: 0.0,
          actions: <Widget>[
            TextButton.icon(
              icon: Icon(Icons.person),
              label: Text("退出登录"),
              onPressed: () async {
                await _auth.signOut();
              },
            )
          ],
        ),
        body: const WatchList(),
      ),
    );
  }
}

Database.dart(翻译注释后的代码)

import "package:cloud_firestore/cloud_firestore.dart";
import "package:watch_hub/models/watch.dart";
import 'package:watch_hub/screens/home/home.dart';

class DatabaseService {
  final String? uid;
  DatabaseService({this.uid});
  // 集合引用
  final CollectionReference users =
      FirebaseFirestore.instance.collection("Users");

  final CollectionReference watch_list =
      FirebaseFirestore.instance.collection("watch_hub");
  dynamic brand = "Longines";
  dynamic model = "Aviation Big Eye";
  

  Future setUserData(
      String email, String address, String fullName, String phone) async {
    return await users.doc(uid).set({
      "email": email,
      "address": address,
      "fullName": fullName,
      "phone": phone,
    });
  }

  // 从快照生成手表列表
  List<Watch> _watchListFromSnapshot(QuerySnapshot snapshot) {
    print("无选项 $option");
    return snapshot.docs.map((doc) {
      return Watch(
        id: doc['id'] ?? '',
        brand: doc['brand'] ?? '',
        model: doc['model'] ?? '',
        type: doc['type'] ?? '',
        popularity: doc['popularity'] ?? 0,
        price: doc['price'].toString(),
        image: doc['image'] ?? '',
      );
    }).toList();
  }

  // 获取手表列表
  Stream<List<Watch>> get watches {
    dynamic option = Home().currentOption;
    /* 打印此值时,option始终为0,因为这是它在home.dart中的初始值 */
    print("选项值为 $option"); 
    late Query filter;

    option is String
        ? filter = watch_list.where("brand", isEqualTo: option)
        : filter = watch_list.where("brand", isNotEqualTo: true);


    print(watch_list);
    return filter.snapshots().map(_watchListFromSnapshot);
  }
}

解决方案

问题根源

你在Database类里通过Home().currentOption获取值时,实际是创建了一个全新的Home实例,这个新实例的currentOption自然是初始值0,而非界面上正在使用的Home实例的最新值。

修复步骤

  1. 修改DatabaseService,接收外部传入的过滤参数
    把watches getter改成带参数的方法,让外部可以主动传入最新的选项:
// 修改DatabaseService中的watches部分
Stream<List<Watch>> getWatches(dynamic option) {
  print("选项值为 $option"); 
  late Query filter;

  option is String
      ? filter = watch_list.where("brand", isEqualTo: option)
      : filter = watch_list.where("brand", isNotEqualTo: true);

  return filter.snapshots().map(_watchListFromSnapshot);
}
  1. 在Home类中动态传递最新的currentOption
    使用StreamProvider.builder替代StreamProvider.value,这样每次setState后都能重新构建包含最新选项的Stream:
// 修改Home类的build方法中的StreamProvider部分
@override
Widget build(BuildContext context) {
  return StreamProvider<List<Watch>>.builder(
    initialData: const [],
    builder: (context, child) {
      return DatabaseService().getWatches(widget.currentOption);
    },
    child: Scaffold(
      // 原有的Scaffold内容保持不变
      ...
    ),
  );
}
  1. 优化变量存储(可选但推荐)
    按照Flutter设计规范,将状态变量移到State类中(StatefulWidget本身应保持不可变):
class Home extends StatefulWidget {
  Home({super.key});
  @override
  State<Home> createState() => _HomeState();
}

class _HomeState extends State<Home> {
  final AuthService _auth = AuthService();
  dynamic currentOption = options[0]; // 变量移至State类

  @override
  Widget build(BuildContext context) {
    return StreamProvider<List<Watch>>.builder(
      initialData: const [],
      builder: (context, child) {
        return DatabaseService().getWatches(currentOption);
      },
      child: Scaffold(
        drawer: Drawer(
          child: Column(
            children: <Widget>[
              // 修改Radio的groupValue和onChanged逻辑
              ListTile(
                title: const Text('无'),
                leading: Radio<dynamic>(
                  value: options[0],
                  groupValue: currentOption,
                  onChanged: (value) {
                    setState(() {
                      currentOption = value;
                      print("当前值为 ${currentOption}");
                    });
                  },
                ),
              ),
              // 其余Radio按钮同理修改
              ...
            ],
          ),
        ),
        // 其他内容保持不变
        ...
      ),
    );
  }
}

原理说明

  • 通过带参数的getWatches方法,主动将最新过滤选项传递给DatabaseService,避免创建新的Home实例获取初始值。
  • StreamProvider.builder会在每次setState后重新生成Stream,确保Provider监听的是最新的过滤结果流。
  • 将状态变量移至State类符合Flutter的状态管理规范,保证StatefulWidget的不可变性。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 00:02:32