flame-engine / flame

A Flutter based game engine.
https://flame-engine.org
MIT License
9.15k stars 895 forks source link

When remove component : Null check operator used on a null value. #3215

Open pakeng opened 2 months ago

pakeng commented 2 months ago

What happened?

      Non-fatal Exception: io.flutter.plugins.firebase.crashlytics.FlutterError: Null check operator used on a null value. Error thrown .
   at Component._remove.<fn>(component.dart:971)
   at Iterable.every(dart:core)
   at Component.propagateToChildren(component.dart:374)
   at Component._remove(component.dart:961)
   at Component.handleLifecycleEventRemove(component.dart:820)
   at ComponentTreeRoot.processLifecycleEvents(component_tree_root.dart:95)
   at FlameGame.updateTree(flame_game.dart:158)
   at FlameGame.update(flame_game.dart:152)
   at GameWidgetState.build.<fn>.<fn>.<fn>(game_widget.dart:387)
   at GameWidgetState._protectedBuild(game_widget.dart:228)
   at GameWidgetState.build.<fn>.<fn>(game_widget.dart:376)
   at _LayoutBuilderElement._layout.layoutCallback(layout_builder.dart:139)
   at BuildOwner.buildScope(framework.dart:2844)
   at _LayoutBuilderElement._layout(layout_builder.dart:173)
   at RenderObject.invokeLayoutCallback.<fn>(object.dart:2686)
   at PipelineOwner._enableMutationsToDirtySubtrees(object.dart:1097)
   at RenderObject.invokeLayoutCallback(object.dart:2686)
   at RenderConstrainedLayoutBuilder.rebuildIfNecessary(layout_builder.dart:248)
   at _RenderLayoutBuilder.performLayout(layout_builder.dart:331)
   at RenderObject._layoutWithoutResize(object.dart:2414)
   at PipelineOwner.flushLayout(object.dart:1051)
   at PipelineOwner.flushLayout(object.dart:1064)
   at RendererBinding.drawFrame(binding.dart:582)
   at WidgetsBinding.drawFrame(binding.dart:991)
   at RendererBinding._handlePersistentFrameCallback(binding.dart:448)
   at SchedulerBinding._invokeFrameCallback(binding.dart:1386)
   at SchedulerBinding.handleDrawFrame(binding.dart:1311)
   at SchedulerBinding._handleDrawFrame(binding.dart:1169)

What do you expect?

 void _remove() {
    assert(_parent != null, 'Trying to remove a component with no parent');

    _parent!.children.remove(this);
    propagateToChildren(
      (Component component) {
        component
          ..onRemove()
          .._unregisterKey()
          .._clearMountedBit()
          .._clearRemovingBit()
          .._setRemovedBit()
          .._removeCompleter?.complete()   // here is async func call. when exec, where jump other code and may change _parent value, it cause null pointer check error?
          .._removeCompleter = null
   //        .._parent!.onChildrenChanged(component, ChildrenChangeType.removed)  // error in here
          .._parent?.onChildrenChanged(component, ChildrenChangeType.removed)   // may use ? instead !
          .._parent = null;
        return true;
      },
      includeSelf: true,
    );
  }

How can we reproduce this?

on flame-1.17.0 and flutter 3.19.5

What steps should take to fix this?

No response

Do have an example of where the bug occurs?

No response

Relevant log output

No response

Execute in a terminal and put output into the code block below

Output of: flutter doctor -v

Affected platforms

Android

Other information

No response

Are you interested in working on a PR for this?

spydon commented 2 months ago

You're trying to remove a component that doesn't have a parent, if running in debug mode you would have hit the assertion in the top before this. I'd suggest you look into where you're trying to remove an unmounted component.

pakeng commented 2 months ago

@spydon OK, let me a try.

spydon commented 1 month ago

@pakeng did you find out anything more?