Reputation: 3
Problem: I'm developing a Flutter application that receives EEG signals from a device and visualizes them using Syncfusion charts. However, the app starts to lag significantly when the visualization tab is open. The visualizations and all UI processes running on the UI isolate begin to slow down. Below is the relevant code for reference. I suspect the periodic updates and rendering might be causing the issue, but I'm not sure how to optimize it.
import 'dart:async';
import 'package:syncfusion_flutter_charts/charts.dart';
class Exg extends StatefulWidget {
final ExploreDevice exploreDevice;
late final ExgSubscriber subscriber;
Exg({super.key, required this.exploreDevice}) {
subscriber = exploreDevice.exgSubscriber;
}
@override
State<Exg> createState() => _ExgState();
}
class _ExgState extends State<Exg> {
final int channelCount = 8;
List<List<ExgData>> chartData = [];
final List<ChartSeriesController> _chartSeriesControllers = [];
Timer? _chartUpdateTimer;
@override
void initState() {
// Update chart data periodically
_chartUpdateTimer = Timer.periodic(const Duration(milliseconds: 100), (timer) {
//normally widget has a subscriber field but it is removed to simplify question
ExgSubscriber subscriber = widget.subscriber;
// Skip corrupted packet
if (subscriber.data.length > widget.exploreDevice.getChannelCount().value) {
return;
}
//init chartData list if it is not
for (int i = 0; i < subscriber.data.length; i++) {
if (chartData.length <= i) {
chartData.add(List.from(subscriber.data[i]));
setState(() {});
continue;
}
//find last how many new packets have arrived and add them to the list
int indexLast = subscriber.data[i].length -
subscriber.data[i].lastIndexWhere((element) => element.time ==
chartData[i].last.time) - 1;
chartData[i].addAll(subscriber.data[i].sublist(subscriber.data[i].length -
indexLast));
//add new packets to the list. Remove old packets if array size exceeds it's limit
if (chartData[i].length >= 400) {
chartData[i].removeRange(0, indexLast);
_chartSeriesControllers[i].updateDataSource(
addedDataIndexes: List<int>.generate(
indexLast, (index) => chartData[i].length - indexLast + index),
removedDataIndexes: List<int>.generate(indexLast, (index) => index),
);
} else {
_chartSeriesControllers[i].updateDataSource(
addedDataIndexes: List<int>.generate(indexLast,
(index) => chartData[i].length - indexLast + index),
);
}
}
});
super.initState();
}
@override
void dispose() {
_chartUpdateTimer?.cancel();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
children: _buildCharts(),
),
),
),
);
}
List<Widget> _buildCharts() {
List<Widget> chartsList = [];
for (int i = 0; i < widget.channelCount; i++) {
chartsList.add(Card(
child: SizedBox(
child: SfCartesianChart(
title: ChartTitle(
text: "ch${i + 1}",
alignment: ChartAlignment.center,
),
series: <CartesianSeries<ExgData, String>>[
LineSeries<ExgData, String>(
onRendererCreated: (ChartSeriesController controller) {
if (_chartSeriesControllers.length <= i) {
_chartSeriesControllers.add(controller);
} else {
_chartSeriesControllers[i] = controller;
}
},
dataSource: chartData.isNotEmpty ? chartData[i] : [],
xValueMapper: (ExgData exg, _) => exg.time,
yValueMapper: (ExgData exg, _) => exg.value,
),
],
),
),
));
}
return chartsList;
}
}
Details:
Issues:
Questions:
Note: I followed the best practice that they suggest on the syncfusion documentation. Documentation link
Upvotes: 0
Views: 96