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

Flutter中使用StreamBuilder展示Algolia搜索结果无内容求助

问题:Flutter中调用Algolia搜索后StreamBuilder无结果显示

我是Flutter新手,正在开发一个在TextField输入文本并调用Algolia进行搜索的程序。输入文本后Algolia能正常处理,但屏幕上没有返回任何结果。我怀疑是否是使用StreamBuilder导致的问题(换成FutureBuilder会不会更好?),希望能得到帮助。

目前没有报错信息,但StreamBuilder中的snapshot为null,不过Future中的hits能正常打印出长度。

代码示例

import 'dart:async';
import 'package:algolia/algolia.dart';
import 'package:flutter/material.dart';

import '../../main.dart';

class Application {
  static final Algolia algolia = Algolia.init(
    applicationId: '78CZVABC2W',
    apiKey: 'c2377e7faad9a408d5867b849f25fae4',
  );
}

class Search extends StatefulWidget {
  @override
  _SearchState createState() => _SearchState();
}

class _SearchState extends State<Search> {
  StreamController<List<AlgoliaObjectSnapshot>> searchController = StreamController();

  Future searchFireStore(word) async {
    Algolia algolia = Application.algolia;
    AlgoliaQuery query = algolia.instance.index("rigaku_index").query(word);
    AlgoliaQuerySnapshot snap = await query.getObjects();
    List<AlgoliaObjectSnapshot> hits = snap.hits;
    searchController.add(hits);
    print(hits.length);
  }

  final _algilia = Application.algolia;

  @override
  void dispose() {
    searchController.close();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: SearchItems(),
        backgroundColor: Colors.white,
      ),
      body: Column(
        children: <Widget>[
          Expanded(
            child: StreamBuilder(
              stream: searchController.stream,
              builder: (context,AsyncSnapshot snapshot) {
                if (snapshot.hasData) {
                  return ListView.builder(
                    itemCount: snapshot.data.length,
                    itemBuilder: (context, index) {
                      return Text((snapshot.data[index].data['zyugyoumei']));
                    },
                  );
                } else {
                  return Center(
                    child: Text("No Data"),
                  );
                }
              },
            ),
          )
        ],
      ),
    );
  }
}

class SearchItems extends StatefulWidget {
  @override
  _SearchItemsState createState() => _SearchItemsState();
}

class _SearchItemsState extends State<SearchItems> {
  String searchWord = "";

  @override
  Widget build(BuildContext context) {
    return TextField(
        decoration: const InputDecoration(
          hintText: '検索',
        ),
        controller: TextEditingController(text: searchWord),
        onChanged: (String text) {
          setState(() {
            searchWord = text;
          });
        },
        onSubmitted: (searchWord) =>_SearchState().searchFireStore(searchWord));
  }
}

解决方案

核心问题定位

你在SearchItems的onSubmitted里直接创建了_SearchState的新实例来调用searchFireStore,但这个新实例和页面上正在运行的_SearchState完全不是同一个对象。新实例的searchController发送的数据,页面上绑定的StreamBuilder根本接收不到,这就是为什么hits能打印但UI没更新的原因。

修复步骤

  1. 给SearchItems添加搜索回调
    修改SearchItems,通过回调函数将搜索事件传递给父组件的_SearchState,而不是创建新的State实例:
class SearchItems extends StatefulWidget {
  // 定义搜索回调
  final Function(String) onSearchSubmitted;

  // 构造函数接收回调
  const SearchItems({required this.onSearchSubmitted, Key? key}) : super(key: key);

  @override
  _SearchItemsState createState() => _SearchItemsState();
}

然后在TextField的onSubmitted中调用这个回调:

onSubmitted: (searchWord) => widget.onSearchSubmitted(searchWord)
  1. 在父组件中传递回调
    在Search的build方法里,将searchFireStore方法作为回调传递给SearchItems:
appBar: AppBar(
  title: SearchItems(onSearchSubmitted: searchFireStore),
  backgroundColor: Colors.white,
),
  1. 优化StreamBuilder的状态处理(可选)
    为了提升用户体验,可以完善StreamBuilder的状态判断,处理加载中和空数据的情况:
builder: (context, AsyncSnapshot snapshot) {
  // 处理加载状态
  if (snapshot.connectionState == ConnectionState.waiting) {
    return Center(child: CircularProgressIndicator());
  }
  // 有数据且不为空时展示列表
  if (snapshot.hasData && snapshot.data.isNotEmpty) {
    return ListView.builder(
      itemCount: snapshot.data.length,
      itemBuilder: (context, index) {
        // 处理字段可能为null的情况
        return Text(snapshot.data[index].data['zyugyoumei'] ?? '无名称');
      },
    );
  } else {
    return Center(
      child: Text("暂无搜索结果"),
    );
  }
}

StreamBuilder vs FutureBuilder的选择

  • StreamBuilder:适合实时搜索场景(比如输入文字时自动触发搜索),可以多次向流中发送数据更新UI,你的场景用它完全没问题,之前的问题和它无关。
  • FutureBuilder:适合单次搜索场景,每次提交搜索时需要更新State中的Future变量来触发UI刷新。如果只是提交时搜索一次,也可以用,但StreamBuilder在多次搜索的场景下更灵活。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.30 04:55:21