问题描述
我目前正在开发一个 Flutter 应用程序,该应用程序将在折线图上实时绘制来自 BLE 设备的数据(其中数据将以示波器样式格式显示)。作为实时 BLE 数据的占位符,我使用计时器回调来生成和绘制带有“charts_Flutter”包的正弦波。到目前为止,一切似乎都在起作用。但是,当更新周期小于 500 毫秒时,图表渲染似乎很难跟上(例如,将其设置为 200 毫秒会导致一切冻结)。在我开始尝试不同的软件包之前,我想看看是否有人有提示或建议来尝试加快速度。我可能只是在状态管理等方面做错了。因为我对颤振没有经验。代码很短,所以我在下面包含了两个项目文件。谢谢。
main.dart
import 'package:Flutter/material.dart';
import 'package:charts_Flutter/Flutter.dart';
import 'package:provider/provider.dart';
import 'package:tuple/tuple.dart';
import 'models/graph_data_model.dart';
void main() => runApp(new GraphDataApp());
class GraphDataApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MultiProvider(
providers: [
ChangeNotifierProvider<GraphDataModel>(
create: (context) => GraphDataModel()),],child: MaterialApp(
title: 'Data Plotter',theme: ThemeData(
primarySwatch: Colors.blue,),initialRoute: '/',routes: {
'/': (context) => MyApp(),},);
}
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("Data Plotter")),body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,children: <Widget>[
GraphDataWidget(),);
}
}
class GraphDataWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Padding(
padding: EdgeInsets.all(5.0),child: SizedBox(
height: 400.0,child: Selector<GraphDataModel,Tuple2<GraphDataModel,double>>(
selector: (_,graphDataModel) {
return Tuple2(graphDataModel,graphDataModel.elapsedtime);
},builder: (context,selectorTuple,child) {
GraphDataModel graphDataModel = selectorTuple.item1;
return LineChart(
graphDataModel.series.toList(),animate: false,domainAxis: NumericAxisspec(
viewport: NumericExtents(graphDataModel.domainStart,graphDataModel.domainEnd))
);
},);
}
}
graph_data_model.dart
import 'dart:async';
import 'dart:math';
import 'package:charts_Flutter/Flutter.dart';
import 'package:Flutter/material.dart';
const UPDATE_INTERVAL = 500;
const MAX_TIME_INTERVAL = 10.0;
const MAX_DATA_POINTS = ((MAX_TIME_INTERVAL * 1000) / UPDATE_INTERVAL);
class GraphDataModel extends ChangeNotifier {
bool _running = false;
int _startTime;
double elapsedtime;
List<Series<PlotPoint,double>> series;
GraphDataModel() {
// initialize the data series
series = [
Series<PlotPoint,double>(
id: 'Sine',colorFn: (_,__) => MaterialPalette.blue.shadeDefault,domainFn: (PlotPoint point,_) => point.time,measureFn: (PlotPoint point,_) => point.value,data: <PlotPoint>[PlotPoint(0,0)],];
// initialize the start time and start the timer
_startTime = DateTime.Now().millisecondsSinceEpoch;
Timer.periodic(Duration(milliseconds: UPDATE_INTERVAL),_timerCallback);
}
// getters
num get domainStart => _running ? (series.first.data.first.time) : 0;
num get domainEnd => _running ? (series.first.data.last.time) : 1;
void _timerCallback(Timer t) {
final currentTime = DateTime.Now().millisecondsSinceEpoch;
// find the elapsed time in seconds
elapsedtime = (currentTime - _startTime).todouble() / 1000.0;
// find the sine value based on the elapsed time
final yVal = sin((2.0 * pi * elapsedtime) / 10.0);
// add the latest data point to the series
series.first.data.add(PlotPoint(elapsedtime,yVal));
// remove the first element in the list to create oscilloscope scrolling effect
if(series.first.data.length > MAX_DATA_POINTS.toInt() || !_running) {
series.first.data.removeAt(0);
}
_running = true;
notifyListeners();
}
}
class PlotPoint {
final double time;
final double value;
PlotPoint(this.time,this.value);
}
解决方法
我得出的结论是,“charts_flutter”根本不适合实时数据。我最终通过扩展自定义画家编写了自己的示波器小部件,并且没有明显的性能问题。