flutter:BLoC Builder 没有更新,尽管我在调试器中看到 new/different 状态
flutter: BLoC Builder not updating, though I see new/different state in debugger
我今天发生的第二件怪事。当我在 bloc.dart(库,而不是我的文件)中跟踪调试器时,我看到 transition.nextState == state && _emitted
是 false
,它不会更新我的小部件(nextState 的列表大小为 2,state 有10 - _emitted 为真)。据我了解,构建器应该没问题,还有其他地方可以查看为什么它不更新吗?
在展示代码之前先解释一下逻辑
我在应用启动时使用
获取我的数据
BlocProvider(create: (context) =>
LogicGraphsPStmntBloc(logicGraphsRepository:
logicGraphsRepository)..add(LogicGraphsNextProblemRequested()),
这是一个包含 10 个字符串的列表,我将其存储在我的 _bloc.dart 文件中(不确定这是否是最先进的)
这 10 个字符串通过状态 LogicGraphsPStmntLoadSuccess(statements)
发送并正确呈现为按钮
如果我点击一个按钮,只会显示第一个和选择的字符串。使用 onPressed: () {BlocProvider.of<LogicGraphsPStmntBloc>(context).add(LogicGraphsPStmntCollapsed(statement: index-1));},
正确触发事件
这会正确触发状态 yield LogicGraphsPStmntLoadSuccess(statementsShown);
,现在列表中只有 2 个元素(与步骤 3 中的 10 个元素相比),但它不会导致重新呈现
如果我使用调试器进入状态,我可以看到两种状态都有不同数量的元素。
我的状态
abstract class LogicGraphsPStmntState extends Equatable {
const LogicGraphsPStmntState();
@override
List<Object> get props => [];
}
class LogicGraphsPStmntLoadSuccess extends LogicGraphsPStmntState {
const LogicGraphsPStmntLoadSuccess([this.statements = const []]);
final List<String> statements;
@override
List<Object> get props => [];
@override
String toString() => 'LogicGraphsPStmntLoadSuccess { statements: $statements }';
}
我的集团(不完全是,因为我的子函数中用于释放状态的代码没有达到 my other issue 中的描述。所以目前我在 mapEventToState=[= 中将这些子函数行作为意大利面条24=]
class LogicGraphsPStmntBloc extends Bloc<LogicGraphsPStmntEvent, LogicGraphsPStmntState> {
LogicGraphsPStmntBloc({@required this.logicGraphsRepository}) : super(LogicGraphsPStmntInProgress());
final LogicGraphsRepository logicGraphsRepository;
List<String> statements;
int currentProblem = -1;
@override
Stream<LogicGraphsPStmntState> mapEventToState(LogicGraphsPStmntEvent event) async* {
if (event is LogicGraphsNextProblemRequested) {
_mapLGPStmntNewProblemRequested();
_mapLGPStmntLoadRequested(currentProblem);
}
else if (event is LogicGraphsPStmntLoadRequested) {
_mapLGPStmntLoadRequested(currentProblem);
}
else if (event is LogicGraphsPStmntCollapsed) {
_mapLGPStmntCollapseRequested(event);
}
Stream<LogicGraphsPStmntState> _mapLGPStmntNewProblemRequested() async* {
try {
currentProblem =
await getNextProblem(currentProblem == null ? -1 : currentProblem);
statements =
await logicGraphsRepository.getProblemStmntList(currentProblem);
_mapLGPStmntLoadRequested(currentProblem);
} catch (_) {
yield LogicGraphsPStmntLoadFailure();
}
}
Stream<LogicGraphsPStmntState> _mapLGPStmntLoadRequested(int problem) async* {
try {
yield LogicGraphsPStmntLoadSuccess(statements);
} catch (_) {
yield LogicGraphsPStmntLoadFailure();
}
}
Stream<LogicGraphsPStmntState> _mapLGPStmntCollapseRequested(
LogicGraphsPStmntCollapsed event) async* {
List<String> statementsShown = [];
statementFocussed = event.statement;
statementsShown.add(statements[0]);
statementsShown.add(statements[statementFocussed]);
yield LogicGraphsPStmntLoadSuccess(statementsShown);
}
}
我的小部件
class LogicGraphPage extends StatelessWidget {
final LogicGraphsRepository logicGraphsRepository = LogicGraphsRepository(
logicGraphsApiClient: LogicGraphsApiClient());
@override
Widget build(BuildContext context) {
return CupertinoPageScaffold(
child: BlocProvider(
create: (context) =>
LogicGraphsPStmntBloc(logicGraphsRepository: logicGraphsRepository)
..add(LogicGraphsNextProblemRequested()),
child:BlocBuilder<LogicGraphsPStmntBloc, LogicGraphsPStmntState>(
builder: (context, state) {
if (state is LogicGraphsPStmntLoadSuccess) {
final List<String> statements = state.statements;
return ListView.builder(
itemCount: statements.length,
itemBuilder: (BuildContext context, int index) {
return CupertinoButton(
padding: EdgeInsets.all(0),
child: Text(statements[index])
onPressed: () {BlocProvider.of<LogicGraphsPStmntBloc>(context).add(LogicGraphsPStmntCollapsed(statement: index-1));},
);
});
}
else return Container();
}
)
),
);
}
}
bloc.dart 库中的函数,我假设新状态已发出。您会看到行 if (transition.nextState == state && _emitted) return;
。下一个状态有 2 个元素,状态有 10 个,_emitted 为真,所以我假设代码继续。而是触发 return 并跳过带有 emit(transition.nextState);
的行。
非常感谢任何帮助,因为这是我第一次使用 BLoC/equatable 并且一般来说 flutter 对我来说还是很新的。但我在进步!
void _bindEventsToStates() {
_transitionSubscription = transformTransitions(
transformEvents(
_eventController.stream,
(event) => mapEventToState(event).map(
(nextState) => Transition(
currentState: state,
event: event,
nextState: nextState,
),
),
),
).listen(
(transition) {
if (transition.nextState == state && _emitted) return; // <<<<<<<<<<<
try {
onTransition(transition);
emit(transition.nextState);
} on dynamic catch (error, stackTrace) {
onError(error, stackTrace);
}
_emitted = true;
},
onError: onError,
);
}
我猜 bloc 无法分辨 LogicGraphsPStmntLoadSuccess(statements)
和 LogicGraphsPStmntLoadSuccess(statementsShown)
之间的区别,因为它们是相同的状态,我认为它无法发现不同参数之间的差异。
所以我建议这样做:
在产生 LogicGraphsPStmntLoadSuccess(statementsShown)
之前尝试产生一个“切换”状态,就像我之前不知道 LogicGraphsPStmntChangeStatement
一样。
所以:
yield LogicGraphsPStmntChangeStatement;
yield LogicGraphsPStmntLoadSuccess(statementsShown);
这应该可以解决问题。
我今天发生的第二件怪事。当我在 bloc.dart(库,而不是我的文件)中跟踪调试器时,我看到 transition.nextState == state && _emitted
是 false
,它不会更新我的小部件(nextState 的列表大小为 2,state 有10 - _emitted 为真)。据我了解,构建器应该没问题,还有其他地方可以查看为什么它不更新吗?
在展示代码之前先解释一下逻辑
我在应用启动时使用
获取我的数据BlocProvider(create: (context) => LogicGraphsPStmntBloc(logicGraphsRepository: logicGraphsRepository)..add(LogicGraphsNextProblemRequested()),
这是一个包含 10 个字符串的列表,我将其存储在我的 _bloc.dart 文件中(不确定这是否是最先进的)
这 10 个字符串通过状态
LogicGraphsPStmntLoadSuccess(statements)
发送并正确呈现为按钮如果我点击一个按钮,只会显示第一个和选择的字符串。使用
正确触发事件onPressed: () {BlocProvider.of<LogicGraphsPStmntBloc>(context).add(LogicGraphsPStmntCollapsed(statement: index-1));},
这会正确触发状态
yield LogicGraphsPStmntLoadSuccess(statementsShown);
,现在列表中只有 2 个元素(与步骤 3 中的 10 个元素相比),但它不会导致重新呈现如果我使用调试器进入状态,我可以看到两种状态都有不同数量的元素。
我的状态
abstract class LogicGraphsPStmntState extends Equatable {
const LogicGraphsPStmntState();
@override
List<Object> get props => [];
}
class LogicGraphsPStmntLoadSuccess extends LogicGraphsPStmntState {
const LogicGraphsPStmntLoadSuccess([this.statements = const []]);
final List<String> statements;
@override
List<Object> get props => [];
@override
String toString() => 'LogicGraphsPStmntLoadSuccess { statements: $statements }';
}
我的集团(不完全是,因为我的子函数中用于释放状态的代码没有达到 my other issue 中的描述。所以目前我在 mapEventToState=[= 中将这些子函数行作为意大利面条24=]
class LogicGraphsPStmntBloc extends Bloc<LogicGraphsPStmntEvent, LogicGraphsPStmntState> {
LogicGraphsPStmntBloc({@required this.logicGraphsRepository}) : super(LogicGraphsPStmntInProgress());
final LogicGraphsRepository logicGraphsRepository;
List<String> statements;
int currentProblem = -1;
@override
Stream<LogicGraphsPStmntState> mapEventToState(LogicGraphsPStmntEvent event) async* {
if (event is LogicGraphsNextProblemRequested) {
_mapLGPStmntNewProblemRequested();
_mapLGPStmntLoadRequested(currentProblem);
}
else if (event is LogicGraphsPStmntLoadRequested) {
_mapLGPStmntLoadRequested(currentProblem);
}
else if (event is LogicGraphsPStmntCollapsed) {
_mapLGPStmntCollapseRequested(event);
}
Stream<LogicGraphsPStmntState> _mapLGPStmntNewProblemRequested() async* {
try {
currentProblem =
await getNextProblem(currentProblem == null ? -1 : currentProblem);
statements =
await logicGraphsRepository.getProblemStmntList(currentProblem);
_mapLGPStmntLoadRequested(currentProblem);
} catch (_) {
yield LogicGraphsPStmntLoadFailure();
}
}
Stream<LogicGraphsPStmntState> _mapLGPStmntLoadRequested(int problem) async* {
try {
yield LogicGraphsPStmntLoadSuccess(statements);
} catch (_) {
yield LogicGraphsPStmntLoadFailure();
}
}
Stream<LogicGraphsPStmntState> _mapLGPStmntCollapseRequested(
LogicGraphsPStmntCollapsed event) async* {
List<String> statementsShown = [];
statementFocussed = event.statement;
statementsShown.add(statements[0]);
statementsShown.add(statements[statementFocussed]);
yield LogicGraphsPStmntLoadSuccess(statementsShown);
}
}
我的小部件
class LogicGraphPage extends StatelessWidget {
final LogicGraphsRepository logicGraphsRepository = LogicGraphsRepository(
logicGraphsApiClient: LogicGraphsApiClient());
@override
Widget build(BuildContext context) {
return CupertinoPageScaffold(
child: BlocProvider(
create: (context) =>
LogicGraphsPStmntBloc(logicGraphsRepository: logicGraphsRepository)
..add(LogicGraphsNextProblemRequested()),
child:BlocBuilder<LogicGraphsPStmntBloc, LogicGraphsPStmntState>(
builder: (context, state) {
if (state is LogicGraphsPStmntLoadSuccess) {
final List<String> statements = state.statements;
return ListView.builder(
itemCount: statements.length,
itemBuilder: (BuildContext context, int index) {
return CupertinoButton(
padding: EdgeInsets.all(0),
child: Text(statements[index])
onPressed: () {BlocProvider.of<LogicGraphsPStmntBloc>(context).add(LogicGraphsPStmntCollapsed(statement: index-1));},
);
});
}
else return Container();
}
)
),
);
}
}
bloc.dart 库中的函数,我假设新状态已发出。您会看到行 if (transition.nextState == state && _emitted) return;
。下一个状态有 2 个元素,状态有 10 个,_emitted 为真,所以我假设代码继续。而是触发 return 并跳过带有 emit(transition.nextState);
的行。
非常感谢任何帮助,因为这是我第一次使用 BLoC/equatable 并且一般来说 flutter 对我来说还是很新的。但我在进步!
void _bindEventsToStates() {
_transitionSubscription = transformTransitions(
transformEvents(
_eventController.stream,
(event) => mapEventToState(event).map(
(nextState) => Transition(
currentState: state,
event: event,
nextState: nextState,
),
),
),
).listen(
(transition) {
if (transition.nextState == state && _emitted) return; // <<<<<<<<<<<
try {
onTransition(transition);
emit(transition.nextState);
} on dynamic catch (error, stackTrace) {
onError(error, stackTrace);
}
_emitted = true;
},
onError: onError,
);
}
我猜 bloc 无法分辨 LogicGraphsPStmntLoadSuccess(statements)
和 LogicGraphsPStmntLoadSuccess(statementsShown)
之间的区别,因为它们是相同的状态,我认为它无法发现不同参数之间的差异。
所以我建议这样做:
在产生 LogicGraphsPStmntLoadSuccess(statementsShown)
之前尝试产生一个“切换”状态,就像我之前不知道 LogicGraphsPStmntChangeStatement
一样。
所以:
yield LogicGraphsPStmntChangeStatement;
yield LogicGraphsPStmntLoadSuccess(statementsShown);
这应该可以解决问题。