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

如何在单个Flutter页面中使用flutter_bloc实现两个Bloc Builder并解决报错

解决单个页面中两个BlocBuilder的红屏问题

嘿,我来帮你搞定这个问题!你遇到的“A build function returned null”红屏错误,本质是第二个BlocBuilder的builder回调在某些状态分支下返回了null——这在Flutter里是绝对不允许的,任何build函数都必须返回一个有效的Widget,哪怕是空占位组件也不能return null。

下面给你一个正确的实现示例,假设我们有两个独立的Bloc:CounterBloc(处理计数逻辑)和UserBloc(处理用户信息逻辑):

import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';

// 先定义两个简单的Bloc示例
class CounterBloc extends Bloc<int, int> {
  CounterBloc() : super(0) {
    on<int>((event, emit) => emit(state + 1));
  }
}

class UserBloc extends Bloc<String, String> {
  UserBloc() : super("") {
    on<String>((event, emit) => emit("当前用户:$event"));
  }
}

class DualBlocPage extends StatelessWidget {
  const DualBlocPage({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text("双Bloc示例")),
      body: Row(
        mainAxisAlignment: MainAxisAlignment.spaceAround,
        children: [
          // 第一个BlocBuilder:处理计数
          Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              BlocBuilder<CounterBloc, int>(
                builder: (context, state) {
                  // 必须返回非null的Widget,哪怕状态是初始值
                  return Text(
                    "计数:$state",
                    style: const TextStyle(fontSize: 20),
                  );
                },
              ),
              ElevatedButton(
                onPressed: () => context.read<CounterBloc>().add(1),
                child: const Text("增加计数"),
              ),
            ],
          ),
          // 第二个BlocBuilder:处理用户信息
          Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              BlocBuilder<UserBloc, String>(
                builder: (context, state) {
                  // 关键:这里绝对不能return null!如果状态是空,返回占位Widget
                  if (state.isEmpty) {
                    return const Text("请输入用户名", style: TextStyle(color: Colors.grey));
                  }
                  return Text(
                    state,
                    style: const TextStyle(fontSize: 20),
                  );
                },
              ),
              SizedBox(
                width: 150,
                child: TextField(
                  onSubmitted: (value) => context.read<UserBloc>().add(value),
                  decoration: const InputDecoration(hintText: "输入用户名"),
                ),
              ),
            ],
          ),
        ],
      ),
    );
  }
}

// 在页面入口处提供两个Bloc
void main() {
  runApp(
    MultiBlocProvider(
      providers: [
        BlocProvider(create: (_) => CounterBloc()),
        BlocProvider(create: (_) => UserBloc()),
      ],
      child: const MaterialApp(home: DualBlocPage()),
    ),
  );
}

接下来,给你几个排查和修复的关键点:

  • 检查builder函数的所有分支:确保第二个BlocBuilder的builder里,不管什么状态(初始状态、加载状态、空状态)都有对应的Widget返回,绝对不能出现return null的情况。如果不确定,就给一个默认的占位,比如SizedBox.shrink()或者Container()。
  • 确认Bloc的提供是否正确:如果第二个Bloc没有被正确注入上下文(比如忘记在MultiBlocProvider里添加),也可能导致异常,但你说第一个正常,这个概率较低,不过可以顺便检查一下。
  • 避免在builder里做异步操作:builder是同步执行的,如果你在里面嵌入异步逻辑导致返回null,也会触发这个错误,所有状态处理都要同步完成。

举个错误写法的反例,你一定要避开:

// 错误示例:状态为空时返回null
BlocBuilder<SomeBloc, SomeState>(
  builder: (context, state) {
    if (state.hasData) {
      return Text(state.data);
    }
    // 这里return null会直接触发红屏!
  },
)

改成正确的写法:

// 正确示例:所有分支都返回Widget
BlocBuilder<SomeBloc, SomeState>(
  builder: (context, state) {
    if (state.hasData) {
      return Text(state.data);
    } else if (state.isLoading) {
      return const CircularProgressIndicator();
    }
    // 默认返回占位Widget
    return const SizedBox.shrink();
  },
)

按照这个思路修改后,第二个BlocBuilder就不会再出现红屏报错了。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.06 10:57:52