imaNNeo / fl_chart

FL Chart is a highly customizable Flutter chart library that supports Line Chart, Bar Chart, Pie Chart, Scatter Chart, and Radar Chart.
https://flchart.dev
MIT License
6.85k stars 1.77k forks source link

Null check operator used on a null value #1101

Open ozzy1873 opened 2 years ago

ozzy1873 commented 2 years ago

Describe the bug Non-fatal Exception: io.flutter.plugins.firebase.crashlytics.FlutterError: Null check operator used on a null value. Error thrown Instance of 'ErrorDescription'. at State.setState(framework.dart:1129) at _LineChartState._handleBuiltInTouch(line_chart.dart:108) at RenderBaseChart._notifyTouchEvent(render_base_chart.dart:140) at RenderBaseChart.initGestureRecognizers.(render_base_chart.dart:76) at LongPressGestureRecognizer._checkLongPressMoveUpdate.(long_press.dart:756) at GestureRecognizer.invokeCallback(recognizer.dart:198) at LongPressGestureRecognizer._checkLongPressMoveUpdate(long_press.dart:756) at LongPressGestureRecognizer.handlePrimaryPointer(long_press.dart:652) at PrimaryPointerGestureRecognizer.handleEvent(recognizer.dart:563) at PointerRouter._dispatch(pointer_router.dart:94) at PointerRouter._dispatchEventToRoutes.(pointer_router.dart:139) at _LinkedHashMapMixin.forEach(_LinkedHashMapMixin.java) at PointerRouter._dispatchEventToRoutes(pointer_router.dart:137) at PointerRouter.route(pointer_router.dart:123) at GestureBinding.handleEvent(binding.dart:445) at GestureBinding.dispatchEvent(binding.dart:425) at RendererBinding.dispatchEvent(binding.dart:329) at GestureBinding._handlePointerEventImmediately(binding.dart:380) at GestureBinding.handlePointerEvent(binding.dart:344) at GestureBinding._flushPointerEventQueue(binding.dart:302) at GestureBinding._handlePointerDataPacket(binding.dart:285)

To Reproduce I do not know how to reproduce this issue. It happens in the field in production.

Versions Flutter 3.0.5 fl_chart 0.55.0

imaNNeo commented 2 years ago

I couldn't find the problem. Any more details?

robindijkhof commented 2 years ago

I don't think this is related to this lib. https://github.com/flutter/flutter/issues/81684

HenrikSunvigo commented 1 year ago

We may have to check whether this State object is currently in a tree. It could be fixed by using if (!mounted) return; before using setState in _handleBuiltInTouch()

hm122 commented 1 year ago

Facing the same issue. Was anyone able to fix this?

imaNNeo commented 1 year ago

Any reproducible code?

hm122 commented 1 year ago

Unfortunately no. I'm not able to reproduce it locally. Stacktrace from sentry looks similar as the one above:

_CastError: Null check operator used on a null value
  State.setState (framework.dart:1129)
  _LineChartState._handleBuiltInTouch (line_chart.dart:101)
  _LineChartState._handleBuiltInTouch (line_chart.dart:94)
  RenderBaseChart._notifyTouchEvent (render_base_chart.dart:140)
  RenderBaseChart.initGestureRecognizers.<T> (render_base_chart.dart:68)
  GestureRecognizer.invokeCallback (recognizer.dart:198)
  TapGestureRecognizer.handleTapCancel (tap.dart:636)
  BaseTapGestureRecognizer._checkCancel (tap.dart:303)
  BaseTapGestureRecognizer.rejectGesture (tap.dart:280)
  GestureArenaManager._resolveInFavorOf (arena.dart:262)
  GestureArenaManager._resolve (arena.dart:223)
  GestureArenaEntry.resolve (arena.dart:53)
  OneSequenceGestureRecognizer.resolve (recognizer.dart:306)
  LongPressGestureRecognizer.resolve (long_press.dart:834)
  LongPressGestureRecognizer.didExceedDeadline (long_press.dart:612)
  PrimaryPointerGestureRecognizer.didExceedDeadlineWithEvent (recognizer.dart:591)
  PrimaryPointerGestureRecognizer.addAllowedPointer.<T> (recognizer.dart:535)
  _rootRun (zone.dart:1418)
  _rootRun (zone.dart:1417)
  _CustomZone.run (zone.dart:1328)
  _CustomZone.runGuarded (zone.dart:1236)
  _CustomZone.bindCallbackGuarded.<T> (zone.dart:1276)
  _rootRun (zone.dart:1426)
  _rootRun (zone.dart:1417)
  _CustomZone.run (zone.dart:1328)
  _CustomZone.bindCallback.<T> (zone.dart:1260)
  TickerFuture.whenCompleteOrCancel.thunk (ticker.dart:407)
  _Timer._runTimers (timer_impl.dart:398)
  _Timer._handleMessage (timer_impl.dart:429)
  _Timer._handleMessage (timer_impl.dart:419)
  _RawReceivePortImpl._handleMessage (isolate_patch.dart:192)
imaNNeo commented 1 year ago

_LineChartState._handleBuiltInTouch (line_chart.dart:101)

I think you are right. In a normal situation, touchCallback should not be called when the widget is disposed of. But as we handle gestures, it might take a little time to get a gesture result and in this little time, our widget might be disposed.

So @HenrikSunvigo can you please add your solution in all of the chart types?

ozzy1873 commented 1 year ago

Yes, @HenrikSunvigo is correct. You need to check if the widget is mounted before calling setState.

imaNNeo commented 1 year ago

We did the if (mounted) check in 0.62.0. Please check it out and let me know whether it is fixed or not.

btrautmann commented 1 year ago

I can't speak to this exact issue, but I'm having a similar error on version 0.63.0, and it seems to be this line. In my logs I'm seeing the user navigate away from and back to the chart, but because the chart shows up on multiple screens, I can't say for sure whether it was the screen that would have been disposed that caused the issue.

MediaQuery._of (media_query.dart:1018)
MediaQuery.of (media_query.dart:1013)
LineChartLeaf.createRenderObject (line_chart_renderer.dart:27)
RenderObjectElement.mount (framework.dart:5932)
Element.inflateWidget (framework.dart:3971)
Element.updateChild (framework.dart:3708)
SingleChildRenderObjectElement.mount (framework.dart:6435)
Element.inflateWidget (framework.dart:3971)
Element.updateChild (framework.dart:3708)
SingleChildRenderObjectElement.mount (framework.dart:6435)
Element.inflateWidget (framework.dart:3971)
Element.updateChild (framework.dart:3708)
SingleChildRenderObjectElement.mount (framework.dart:6435)
Element.inflateWidget (framework.dart:3971)
Element.updateChild (framework.dart:3708)
ComponentElement.performRebuild (framework.dart:5111)
Element.rebuild (framework.dart:4805)
ComponentElement._firstBuild (framework.dart:5068)
ComponentElement.mount (framework.dart:5062)
Element.inflateWidget (framework.dart:3971)
MultiChildRenderObjectElement.inflateWidget (framework.dart:6570)
MultiChildRenderObjectElement.mount (framework.dart:6582)
Element.inflateWidget (framework.dart:3971)
Element.updateChild (framework.dart:3708)
_LayoutBuilderElement._layout.layoutCallback (layout_builder.dart:135)
BuildOwner.buildScope (framework.dart:2720)
_LayoutBuilderElement._layout (layout_builder.dart:153)
RenderObject.invokeLayoutCallback.<fn> (object.dart:2506)
PipelineOwner._enableMutationsToDirtySubtrees (object.dart:1062)
RenderObject.invokeLayoutCallback (object.dart:2506)
RenderConstrainedLayoutBuilder.rebuildIfNecessary (layout_builder.dart:228)
_RenderLayoutBuilder.performLayout (layout_builder.dart:313)
RenderObject.layout (object.dart:2395)
RenderBox.layout (box.dart:2386)
RenderPadding.performLayout (shifted_box.dart:238)
RenderObject.layout (object.dart:2395)
RenderBox.layout (box.dart:2386)
ChildLayoutHelper.layoutChild (layout_helper.dart:52)
RenderStack._computeSize (stack.dart:580)
RenderStack.performLayout (stack.dart:607)
RenderObject.layout (object.dart:2395)
RenderBox.layout (box.dart:2386)
RenderAspectRatio.performLayout (proxy_box.dart:594)
RenderObject.layout (object.dart:2395)
RenderBox.layout (box.dart:2386)
ChildLayoutHelper.layoutChild (layout_helper.dart:52)
RenderFlex._computeSizes (flex.dart:808)
RenderFlex.performLayout (flex.dart:903)
RenderObject.layout (object.dart:2395)
RenderBox.layout (box.dart:2386)
RenderPadding.performLayout (shifted_box.dart:238)
RenderObject.layout (object.dart:2395)
RenderBox.layout (box.dart:2386)
RenderProxyBoxMixin.performLayout (proxy_box.dart:122)
RenderObject.layout (object.dart:2395)
RenderBox.layout (box.dart:2386)
RenderProxyBoxMixin.performLayout (proxy_box.dart:122)
_RenderCustomClip.performLayout (proxy_box.dart:1449)
RenderObject.layout (object.dart:2395)
RenderBox.layout (box.dart:2386)
_MeasurementView.performLayout (screenshot.dart:394)
RenderObject._layoutWithoutResize (object.dart:2234)
PipelineOwner.flushLayout (object.dart:1016)
ScreenshotController.longWidgetToUiImage (screenshot.dart:323)
ScreenshotController.captureFromLongWidget (screenshot.dart:287)
ShareChartScreen.build.<fn> (share_chart_screen.dart:53)
_InkResponseState.handleTap (ink_well.dart:1154)
GestureRecognizer.invokeCallback (recognizer.dart:275)
TapGestureRecognizer.handleTapUp (tap.dart:654)
BaseTapGestureRecognizer._checkUp (tap.dart:311)
BaseTapGestureRecognizer.handlePrimaryPointer (tap.dart:244)
PrimaryPointerGestureRecognizer.handleEvent (recognizer.dart:630)
PointerRouter._dispatch (pointer_router.dart:98)
PointerRouter._dispatchEventToRoutes.<fn> (pointer_router.dart:143)
_LinkedHashMapMixin.forEach (dart:collection)
PointerRouter._dispatchEventToRoutes (pointer_router.dart:141)
PointerRouter.route (pointer_router.dart:127)
GestureBinding.handleEvent (binding.dart:465)
GestureBinding.dispatchEvent (binding.dart:445)
RendererBinding.dispatchEvent (binding.dart:331)
GestureBinding._handlePointerEventImmediately (binding.dart:400)
GestureBinding.handlePointerEvent (binding.dart:363)
GestureBinding._flushPointerEventQueue (binding.dart:320)
GestureBinding._handlePointerDataPacket (binding.dart:293)
imaNNeo commented 1 year ago

We can add a fallback value of 1.0 for the line that you mentioned. https://github.com/imaNNeo/fl_chart/blob/04b18d22421ac402fed61308a5ce03c97fa7199e/lib/src/chart/line_chart/line_chart_renderer.dart#L27