A Realtime Chart with Flutter
By: Alfred Schilken
Tags: Realtime, Flutter, Charts

A Realtime Chart with Flutter

The RealTime Chart in action

What you will learn:

How to cut out a chart from the mp_chart package example and integrate it into your app.

How to use Dart DevTools to ensure that there is no memory leak.

Since January I’m experimenting with some private Flutter Apps. Especially I’m investigating how Flutter can be used to control bluetooth devices, develop Desktop Apps, Web Apps, and much more.

For a bluetooth project, I needed to visualise two values in realtime, like on an oscilloscope. I checked the packages on pub.dev and chose the mp_chart package. That package has a nice animated realtime chart on the README page.

Flutter makes it easy to develop the separate widgets of an app in isolation and then stick them together. This can be done with all languages, but the ‘everything is a widget’ principle makes it really easy, without fuss.

On the other side, it is easy to cut out interesting parts (widgets) from an app and work on it further. This is my procedure when I begin using a new package. I look whether it has an example app on github and cut out what I need.

The mp_charts package has a showcase of all supported chart types. There are so many different widgets and I had to find the right one:

BarChartBasic

BarChartBasic2

BarChartHorizontal

BarChartMultiple

BarChartNegative

BarChartSine

BarChartStacked

BarChartStacked2

EvenMoreDynamic

EvenMoreHourly

EvenMoreRealtime

LineChartBasic

LineChartColorful

LineChartCubic

LineChartDualAxis

LineChartFilled

LineChartInvertAxis

LineChartMultiple

LineChartPerformance

OtherChartBubble

OtherChartCandlestick

OtherChartCombined

OtherChartRadar

OtherChartScatterPlot

PieChartBasic

PieChartHalfPie

PieChartValueLines

ScrollingChartManyBar

ScrollingChartMultiple

ScrollingChartTallBar

ScrollingChartViewPager

I found the widget EvenMoreRealtime in the source file mp_chart/example/lib/demo/even_more/realtime.dart . But: this widget has several dependencies on the demo app. To make it independent from the showcase frame I had to do the following changes:

My version no longer extends ActionState but just extends a standard State<>. I removed all overridden methods which are defined in the ActionState class. The code in the overridden getBody() method is moved into the standard overridden build() method. No longer needed imports are removed

After these changes and a rename of the widget to RealTimeChart I could use it in a screen called PulsarScreen, which is the body of the Scaffold of my test app. The following code builds the RealTimeChart on the top of a column.

A ConfigurationWidget below the chart contains a range slider to set the upper and lower limit of the generated values and a slider for the frequency of the generated sinus values. These settings are stored in the class RealtimeDataServiceImpl.

The following snippet shows the original code of the demo example:

And here is the corresponding part of my cut out widget, which can run without the demo frame:

I made some more changes to adapt the widget to my requirements:

The _initController method configures all the colors, text styles, limits of the axes, and much more. All in all, there are x properties you can adjust to your requirements.

The demo widget just calls 1000 times _addEntry() periodically in _updateEntry(). I replaced this with a listen on a — maybe endless — _dataStream.

This _dataStream is provided by an instance of RealtimeDataService , which is injected using the locator of the get_it package. The service ist configured by two sliders and it feeds the stream with two sinus waves.

Stream<DataSet> _dataStream = locator<RealtimeDataService>().dataStream;

For this simple test app, this would be overkill, but I use the same architecture in an app, which also will use this RealtimeChart widget.

The original demo example creates a limited number of new entries with each call of _addMultiple() in memory. For a 'real' realtime app, which runs longer, this would be a remarkable memory leak. Searching google for mpandroidchart realtime chart remove I found a solution in stackoverflow. I searched for mpandroidchart because the README of the package states:

flutter charts just like MPAndroidChart

It’s a big advantage of the mp_charts package, that any problems can probably been solved the same way as with MPAndroidChart. This is good to know if any problems occur or any special case is to be configured.

The solution I found is implemented in the method addWithRemove(). It removes entries as soon as they are no longer visible.

The difference can be checked in the memory view of the Dart DevTools. The following screenshot shows the memory if the calls to removeEntry2 are commented out in addWithRemove():

3290 objects and 154 kB memory are consumed in one minute

Note: To get viable results you have to execute the garbage collector with a click on the gc icon. After that a click on Snapshot shows the count of all objects. Special interest is on the object count of class Entry .

And here are the counts if removeEntry2 ist called:

Only 120 objects and 15 kB are consumed, no matter how long the app runs

Conclusion

The mp_chart package is really useful for realtime charts — and many more chart types. There are so many configurable properties. With little effort, other widgets of the mp_charts package can be cut out from the example and used in own apps. I used also the widget OtherChartRadar as in the following animation. The cut out process is quite similar to the above described steps.

The radar chart of the mp_chart package

The full source of my test app is on Github.