一个网络请求方法不断的接收stream图片流事件,需要将这些图片流展示在Image控件上,这样就能够实现让图片变成视频的效果:
直接上代码
import 'dart:async';
import 'dart:typed_data';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
class TestApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'IPCamera'),
);
}
}
List<int> _bytes = [];
Uint8List lastImageData = Uint8List(0);
class MyHomePage extends StatefulWidget {
final String title;
MyHomePage({this.title});
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
final StreamController _streamController = StreamController();
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Column(
children: [
Container(
height: 60,
child: _topButton(),
),
StreamBuilder(
builder: (BuildContext context, AsyncSnapshot snapshot) {
return Image.memory(
consolidateHttpClientResponseBytes(snapshot.data));
},
stream: _streamController.stream,
initialData: Uint8List(0),
),
],
));
}
Future _loadImagesData() async {
var uri = Uri.parse("http://192.168.4.1:81/stream");
var response = await http.Client().send(http.Request('GET',uri));
response.stream.listen((value) {
print(response.request.toString());
_bytes.addAll(value);
if (lastImageData.length == 36) {
_streamController.sink.add(_bytes);
_bytes = [];
}
lastImageData = Uint8List.fromList(value);
print('当前数据字节长度${(lastImageData.length)}');
});
}
Widget _topButton() {
return Center(
child: TextButton(
style: ButtonStyle(
foregroundColor: MaterialStateProperty.resolveWith(
(states) {
if (states.contains(MaterialState.focused) &&
!states.contains(MaterialState.pressed)) {
//获取焦点时的颜色
return Colors.green;
} else if (states.contains(MaterialState.pressed)) {
//按下时的颜色
return Colors.red;
}
//默认状态使用灰色
return Colors.white;
},
),
padding: MaterialStateProperty.all(EdgeInsets.all(10)),
minimumSize: MaterialStateProperty.all(Size(100, 50)),
backgroundColor: MaterialStateProperty.resolveWith((states) {
//设置按下时的背景颜色
if (states.contains(MaterialState.pressed)) {
return Colors.yellowAccent[200];
}
//默认不使用背景颜色
return Colors.blue;
}),
),
onPressed: () {
_loadImagesData();
},
child: Text('请求')),
);
}
static consolidateHttpClientResponseBytes(data) {
// response.contentLength is not trustworthy when GZIP is involved
// or other cases where an intermediate transformer has been applied
// to the stream.
final List<List<int>> chunks = <List<int>>[];
int contentLength = 0;
chunks.add(data);
contentLength += data.length;
final Uint8List bytes = Uint8List(contentLength);
int offset = 0;
for (List<int> chunk in chunks) {
bytes.setRange(offset, offset + chunk.length, chunk);
offset += chunk.length;
}
return bytes;
}
}
这里的网络请求用的是http框架,没使用dio框架,不知道是我不会用还是本身就没有这种对流请求的方法。
导入的是http库:
http: ^0.13.1
其实这里有个问题,我不知道每次传回来的流啥时候是一张完整的图片流,通过观察数据,发现每次刚接收的时候长度是36,于是做了下处理。但实际上这样是不对的,暂时没有找到解决方案,如果有人知道的话,请不吝赐教。