我的应用旨在使用Flutter scoped_model消耗来自API的实时传感器数据。数据是像这样的JSON数组:
[
{
"id": 4,
"device_name": "fermentero2",
"active_beer": 4,
"active_beer_name": "Sourgobo",
"controller_fridge_temp": "Fridge --.- 1.0 ░C",
"controller_beer_temp": "Beer 28.6 10.0 ░C",
"active_beer_temp": 28.63,
"active_fridge_temp": null,
"active_beer_set": 10,
"active_fridge_set": 1,
"controller_mode": "b"
},
{
"id": 6,
"device_name": "brewpi",
"active_beer": 1,
"active_beer_name": "Amber Ale",
"controller_fridge_temp": null,
"controller_beer_temp": null,
"active_beer_temp": null,
"active_fridge_temp": null,
"active_beer_set": null,
"active_fridge_set": null,
"controller_mode": null
}
]
这些是设备。我的设备模型如下(json注释):
@JsonSerializable(nullable: false)
class Device {
int id;
String device_name;
@JsonKey(nullable: true) int active_beer;
@JsonKey(nullable: true) String active_beer_name;
@JsonKey(nullable: true) String controller_mode; // manual beer/fridge ou perfil
@JsonKey(nullable: true) double active_beer_temp;
@JsonKey(nullable: true) double active_fridge_temp;
@JsonKey(nullable: true) double active_beer_set;
@JsonKey(nullable: true) double active_fridge_set;
Device({
this.id,
this.device_name,
this.active_beer,
this.active_beer_name,
this.controller_mode,
this.active_beer_temp,
this.active_beer_set,
this.active_fridge_set,
});
factory Device.fromJson(Map<String, dynamic> json) => _$DeviceFromJson(json);
Map<String, dynamic> toJson() => _$DeviceToJson(this);
}
我对设备的作用域模型类如下:
class DeviceModel extends Model {
Timer timer;
List<dynamic> _deviceList = [];
List<dynamic> get devices => _deviceList;
set _devices(List<dynamic> value) {
_deviceList = value;
notifyListeners();
}
List _data;
Future getDevices() async {
loading = true;
_data = await getDeviceInfo()
.then((response) {
print('Type of devices is ${response.runtimeType}');
print("Array: $response");
_devices = response.map((d) => Device.fromJson(d)).toList();
loading = false;
notifyListeners();
});
}
bool _loading = false;
bool get loading => _loading;
set loading(bool value) {
_loading = value;
notifyListeners();
}
notifyListeners();
}
我的UI旨在成为显示实时数据的设备的列表(随着传感器数据的更改而重建ui)和每个设备的详细信息页面,还显示实时数据。为此,我正在使用计时器。列出设备的页面正在按预期方式工作,每30秒“刷新”一次:
class DevicesPage extends StatefulWidget {
@override
State<DevicesPage> createState() => _DevicesPageState();
}
class _DevicesPageState extends State<DevicesPage> {
DeviceModel model = DeviceModel();
Timer timer;
@override
void initState() {
model.getDevices();
super.initState();
timer = Timer.periodic(Duration(seconds: 30), (Timer t) => model.getDevices());
}
@override
Widget build(BuildContext) {
return Scaffold(
appBar: new AppBar(
title: new Text('Controladores'),
),
drawer: AppDrawer(),
body: ScopedModel<DeviceModel>(
model: model,
child: _buildListView(),
),
);
}
_buildListView() {
return ScopedModelDescendant<DeviceModel>(
builder: (BuildContext context, Widget child, DeviceModel model) {
if (model.loading) {
return UiLoading();
}
final devicesList = model.devices;
return ListView.builder(
itemBuilder: (context, index) => InkWell(
splashColor: Colors.blue[300],
child: _buildListTile(devicesList[index]),
onTap: () {
Route route = MaterialPageRoute(
builder: (context) => DevicePage(devicesList[index]),
);
Navigator.push(context, route);
},
),
itemCount: devicesList.length,
);
},
);
}
_buildListTile(Device device) {
return Card(
child: ListTile(
leading: Icon(Icons.devices),
title: device.device_name == null
? null
: Text(
device.device_name.toString() ?? "",
),
subtitle: device.active_beer_name == null
? null
: Text(
device.active_beer_temp.toString() ?? "",
),
),
);
}
}
class UiLoading extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
CircularProgressIndicator(),
SizedBox(height: 12),
Text(
'Loading',
style: TextStyle(
fontWeight: FontWeight.bold,
),
),
],
),
);
}
}
详细页面UI也会出现问题,该页面也应该显示实时数据,但其行为类似于无状态窗口小部件,并且在更新模型后不会自行重建:
class DevicePage extends StatefulWidget {
Device device;
DevicePage(this.device);
@override
//State<DevicePage> createState() => _DevicePageState(device);
State<DevicePage> createState() => _DevicePageState();
}
class _DevicePageState extends State<DevicePage> {
DeviceModel model = DeviceModel();
Timer timer;
@override
void initState() {
DeviceModel model = DeviceModel();
super.initState();
timer = Timer.periodic(Duration(seconds: 30), (Timer t) => model.updateDevice());
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: new AppBar(
title: new Text(widget.device.device_name),
),
drawer: AppDrawer(),
body: ScopedModel<DeviceModel>(
model: model,
child: _buildView(widget.device),
),
);
}
_buildView(Device device) {
return ScopedModelDescendant<DeviceModel>(
builder: (BuildContext context, Widget child, DeviceModel model) {
if (model.loading) {
return UiLoading();
}
return Card(
child: ListTile(
leading: Icon(Icons.devices),
title: device.device_name == null
? null
: Text(
device.device_name.toString() ?? "",
),
subtitle: device.active_beer_name == null
? null
: Text(
device.active_beer_temp.toString() ?? "",
),
),
);
},
);
}
}
class UiLoading extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
CircularProgressIndicator(),
SizedBox(height: 12),
Text(
'Loading',
style: TextStyle(
fontWeight: FontWeight.bold,
),
),
],
),
);
}
我想念什么? 提前谢谢
答案 0 :(得分:0)
您似乎正在为DevicePage构建一个新的DeviceModel,这意味着 模型将是您的ui会响应的模型,而不是窗口小部件树中的上一个-您的DevicesPage。
ScopedModel<DeviceModel>(
model: model,
child: _buildView(widget.device),
)
在您的设备页面上,您将一个主体添加到Scaffold中,将ScopedModel替换为:
_buildView(widget.device)
那应该可以解决您的问题。