如何在Flutter Firebase集合的orderBy语句中使用变量?
在Firebase Firestore的orderBy中使用实例变量的解决方案
问题描述
我想在Firebase Firestore集合的orderBy语句里使用类的实例变量(后续还要改成状态变量通过UI控制),但直接在初始化器里用变量会报错。硬编码字符串时代码正常运行,换成变量就提示:
The instance member 'sortBy' can't be accessed in an initializer.
错误代码示例:
import 'package:flutter/material.dart'; import 'package:cloud_firestore/cloud_firestore.dart'; class HomePage extends StatelessWidget { final String sortBy = "timestamp"; final bool sortDesc = true; // 硬编码正常运行 final itemList = FirebaseFirestore.instance .collection("simple") .orderBy("item", descending: false); // 用变量就报错 // .orderBy(sortBy, descending: sortDesc); @override Widget build(BuildContext context) { return StreamBuilder( stream: itemList.snapshots(), builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) { // 省略构建逻辑 ... } ); } }
问题原因
Flutter中,类的成员变量初始化器(直接给itemList赋值的代码块)执行时,类的实例还没完成初始化,所以无法访问其他实例成员(比如sortBy、sortDesc)。
解决方案
把itemList从直接初始化的变量改成返回Stream的方法,这样在调用方法时(比如build方法里),类实例已经初始化完成,就能正常访问实例变量了。
修改后的可运行代码:
import 'package:flutter/material.dart'; import 'package:cloud_firestore/cloud_firestore.dart'; class HomePage extends StatelessWidget { final String sortBy = "timestamp"; final bool sortDesc = true; // 改为返回Stream的方法 Stream<QuerySnapshot<Map<String, dynamic>>> itemList() => FirebaseFirestore.instance .collection("simple") .orderBy(sortBy, descending: sortDesc).snapshots(); @override Widget build(BuildContext context) { return StreamBuilder( stream: itemList(), // 调用方法获取流 builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) { // 省略构建逻辑 ... } ); } }
进阶:通过UI控制排序参数
如果要通过UI操作(比如下拉选择排序字段、切换升降序)控制sortBy和sortDesc,需要把StatelessWidget改成StatefulWidget,将这两个变量放到State类中作为状态变量,更新状态时会触发build方法重新执行,进而获取新的排序流:
示例核心代码:
class HomePage extends StatefulWidget { @override _HomePageState createState() => _HomePageState(); } class _HomePageState extends State<HomePage> { // 把排序参数改成状态变量 String sortBy = "timestamp"; bool sortDesc = true; Stream<QuerySnapshot<Map<String, dynamic>>> get itemList => FirebaseFirestore.instance .collection("simple") .orderBy(sortBy, descending: sortDesc).snapshots(); @override Widget build(BuildContext context) { return Column( children: [ // 下拉菜单切换排序字段 DropdownButton<String>( value: sortBy, items: ["timestamp", "item", "price"].map((e) => DropdownMenuItem(value: e, child: Text(e))).toList(), onChanged: (value) { setState(() { sortBy = value!; }); }, ), // 按钮切换升降序 ElevatedButton( onPressed: () { setState(() { sortDesc = !sortDesc; }); }, child: Text(sortDesc ? "切换为升序" : "切换为降序"), ), // 列表展示区域 Expanded( child: StreamBuilder( stream: itemList, builder: (context, snapshot) { // 省略列表构建逻辑 ... }, ), ), ], ); } }
内容的提问来源于stack exchange,提问作者SqueezeOJ
相关产品推荐
相关产品推荐

