From 75b5213cbf4dfadc69e7ffb87c3f850717f0abe6 Mon Sep 17 00:00:00 2001 From: zmtzawqlp Date: Mon, 22 Mar 2021 23:10:31 +0800 Subject: [PATCH] update memory usage demo --- .../lib/common/utils/crop_editor_helper.dart | 10 +- example/lib/common/utils/vm_helper.dart | 27 +- .../lib/common/widget/memory_usage_chart.dart | 174 +++++++++++++ .../lib/common/widget/memory_usage_view.dart | 245 ++++-------------- example/lib/main.dart | 15 +- .../lib/pages/complex/image_editor_demo.dart | 12 +- .../lib/pages/complex/memory_usage_demo.dart | 2 +- 7 files changed, 268 insertions(+), 217 deletions(-) create mode 100644 example/lib/common/widget/memory_usage_chart.dart diff --git a/example/lib/common/utils/crop_editor_helper.dart b/example/lib/common/utils/crop_editor_helper.dart index 177e97e5..d5672bde 100644 --- a/example/lib/common/utils/crop_editor_helper.dart +++ b/example/lib/common/utils/crop_editor_helper.dart @@ -57,7 +57,7 @@ void _isolateEncodeImage(SendPort port) { }); } -Future?> cropImageDataWithDartLibrary( +Future cropImageDataWithDartLibrary( {required ExtendedImageEditorState state}) async { print('dart library start cropping'); @@ -101,7 +101,7 @@ Future?> cropImageDataWithDartLibrary( } if (src != null) { //handle every frame. - src.frames = src.frames.map((image) { + src.frames = src.frames.map((Image image) { final DateTime time2 = DateTime.now(); //clear orientation image = bakeOrientation(image); @@ -144,7 +144,7 @@ Future?> cropImageDataWithDartLibrary( print('start encode'); final DateTime time4 = DateTime.now(); if (src != null) { - bool onlyOneFrame = src.numFrames == 1; + final bool onlyOneFrame = src.numFrames == 1; //If there's only one frame, encode it to jpg. if (kIsWeb) { fileData = onlyOneFrame ? encodeJpg(src.first) : encodeGifAnimation(src); @@ -158,10 +158,10 @@ Future?> cropImageDataWithDartLibrary( final DateTime time5 = DateTime.now(); print('${time5.difference(time4)} : encode'); print('${time5.difference(time1)} : total time'); - return fileData; + return Uint8List.fromList(fileData!); } -Future?> cropImageDataWithNativeLibrary( +Future cropImageDataWithNativeLibrary( {required ExtendedImageEditorState state}) async { print('native library start cropping'); diff --git a/example/lib/common/utils/vm_helper.dart b/example/lib/common/utils/vm_helper.dart index 4a54e5a6..f3332548 100644 --- a/example/lib/common/utils/vm_helper.dart +++ b/example/lib/common/utils/vm_helper.dart @@ -1,15 +1,26 @@ +import 'dart:async'; import 'dart:developer'; import 'package:collection/collection.dart' show IterableExtension; +import 'package:flutter/foundation.dart'; import 'package:vm_service/utils.dart'; import 'package:vm_service/vm_service.dart'; import 'package:vm_service/vm_service_io.dart'; -class VMHelper { +class VMHelper with ChangeNotifier { factory VMHelper() => _vMHelper; - VMHelper._(); + VMHelper._() { + _startConnect().whenComplete(() { + _timer = Timer.periodic(const Duration(seconds: 2), (Timer timer) { + VMHelper()._updateMemoryUsage().whenComplete(() { + notifyListeners(); + }); + }); + }); + } static final VMHelper _vMHelper = VMHelper._(); // Map memoryInfo = {}; late MemoryUsage mainMemoryUsage; + late Timer _timer; List mainHistoryMemoryInfo = []; // Map> historyMemoryInfo = // >{}; @@ -20,7 +31,7 @@ class VMHelper { late bool connected; VmService? serviceClient; VM? vm; - Future startConnect() async { + Future _startConnect() async { final ServiceProtocolInfo info = await Service.getInfo(); if (info.serverUri == null) { print('service protocol url is null,start vm service fail'); @@ -32,10 +43,10 @@ class VMHelper { connected = true; vm = await serviceClient!.getVM(); - await updateMemoryUsage(); + await _updateMemoryUsage(); } - Future updateMemoryUsage() async { + Future _updateMemoryUsage() async { if (vm != null && connected) { final MemoryUsage memoryUsage = await serviceClient!.getMemoryUsage(main!.id!); @@ -55,6 +66,12 @@ class VMHelper { _count = 0; mainHistoryMemoryInfo.clear(); } + + @override + void dispose() { + _timer.cancel(); + super.dispose(); + } } class MyMemoryUsage { diff --git a/example/lib/common/widget/memory_usage_chart.dart b/example/lib/common/widget/memory_usage_chart.dart new file mode 100644 index 00000000..48c21fe1 --- /dev/null +++ b/example/lib/common/widget/memory_usage_chart.dart @@ -0,0 +1,174 @@ +import 'dart:math'; +import 'dart:ui'; + +import 'package:example/common/utils/vm_helper.dart'; +import 'package:fl_chart/fl_chart.dart'; +import 'package:flutter/material.dart'; +import 'package:intl/intl.dart'; + +class MemoryUsageChart extends StatefulWidget { + @override + _MemoryUsageChartState createState() => _MemoryUsageChartState(); +} + +class _MemoryUsageChartState extends State { + @override + void initState() { + super.initState(); + VMHelper().addListener(updateMemoryUsage); + } + + void updateMemoryUsage() { + if (mounted) { + setState(() {}); + } + } + + @override + void dispose() { + VMHelper().removeListener(updateMemoryUsage); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + if (VMHelper().serviceClient == null) { + return Container(); + } + return Container( + padding: const EdgeInsets.only(left: 30, right: 30, top: 5, bottom: 5), + width: window.physicalSize.width, + height: 200, + child: LineChart( + getData(), + swapAnimationDuration: const Duration(milliseconds: 250), + ), + ); + } + + LineChartData getData() { + final DateTime now = DateTime.now(); + final List data = getLineData(now); + + return LineChartData( + lineTouchData: LineTouchData( + touchTooltipData: LineTouchTooltipData( + tooltipBgColor: Colors.blueGrey.withOpacity(0.8), + ), + touchCallback: (LineTouchResponse touchResponse) {}, + handleBuiltInTouches: true, + ), + gridData: FlGridData( + show: false, + ), + titlesData: FlTitlesData( + bottomTitles: SideTitles( + showTitles: true, + getTextStyles: (double value) => const TextStyle( + color: Color(0xff72719b), + fontWeight: FontWeight.bold, + fontSize: 16, + ), + margin: 10, + getTitles: (double value) { + final int millisecondsSinceEpoch = value.toInt(); + final DateTime dateTime = + DateTime.fromMillisecondsSinceEpoch(millisecondsSinceEpoch); + + return DateFormat('HH:mm').format(dateTime); + }, + interval: const Duration(minutes: 1).inMilliseconds.toDouble(), + ), + leftTitles: SideTitles( + showTitles: true, + getTextStyles: (double value) => const TextStyle( + color: Color(0xff75729e), + fontWeight: FontWeight.bold, + fontSize: 14, + ), + interval: 100, + getTitles: (double value) { + return value.toInt().toString() + 'M'; + }, + margin: 20, + ), + ), + borderData: FlBorderData( + show: true, + border: const Border( + bottom: BorderSide( + color: Color(0xff4e4965), + width: 2, + ), + left: BorderSide( + color: Color(0xff4e4965), + width: 2, + ), + right: BorderSide( + color: Colors.transparent, + ), + top: BorderSide( + color: Colors.transparent, + ), + ), + ), + minX: now + .subtract(const Duration(minutes: 1)) + .millisecondsSinceEpoch + .toDouble(), + maxX: now.millisecondsSinceEpoch.toDouble(), + minY: 0, + maxY: max(500, maxY ?? 0), + lineBarsData: data, + ); + } + + double? minY; + double? maxY; + List getLineData(DateTime now) { + final List data1 = []; + final List data2 = []; + final List data3 = []; + for (final MyMemoryUsage item in VMHelper().mainHistoryMemoryInfo) { + data1.add(FlSpot(item.dataTime.millisecondsSinceEpoch.toDouble(), + item.todouble(item.heapUsage))); + data2.add(FlSpot(item.dataTime.millisecondsSinceEpoch.toDouble(), + item.todouble(item.heapCapacity))); + data3.add(FlSpot(item.dataTime.millisecondsSinceEpoch.toDouble(), + item.todouble(item.externalUsage))); + + final double minValue = + min(min(item.heapUsage, item.heapCapacity), item.externalUsage); + + final double maxValue = + max(max(item.heapUsage, item.heapCapacity), item.externalUsage); + + minY = min(maxY ?? minValue.toDouble(), minValue.toDouble()); + maxY = max(maxY ?? maxValue.toDouble(), maxValue.toDouble()); + } + + return [ + getLineChartBarData(data1, Colors.red), + getLineChartBarData(data2, Colors.blue), + getLineChartBarData(data3, Colors.green), + ]; + } + + LineChartBarData getLineChartBarData(List spots, Color color) { + return LineChartBarData( + spots: spots, + isCurved: true, + colors: [ + color, + ], + barWidth: 2, + isStrokeCapRound: true, + dotData: FlDotData( + show: false, + ), + belowBarData: BarAreaData( + show: false, + ), + ); + } +} diff --git a/example/lib/common/widget/memory_usage_view.dart b/example/lib/common/widget/memory_usage_view.dart index ead9bc28..60b67650 100644 --- a/example/lib/common/widget/memory_usage_view.dart +++ b/example/lib/common/widget/memory_usage_view.dart @@ -1,11 +1,7 @@ -import 'dart:async'; -import 'dart:math'; import 'dart:ui'; import 'package:example/common/utils/vm_helper.dart'; -import 'package:fl_chart/fl_chart.dart'; import 'package:flutter/material.dart'; -import 'package:intl/intl.dart'; import 'package:vm_service/vm_service.dart'; class MemoryUsageView extends StatefulWidget { @@ -14,35 +10,26 @@ class MemoryUsageView extends StatefulWidget { } class _MemoryUsageViewState extends State { - int start = 0; - int end = 0; - late Timer _timer; + double _top = 0; + double _left = 0; @override void initState() { super.initState(); + VMHelper().addListener(updateMemoryUsage); + } - VMHelper().startConnect().whenComplete(() { - setState(() { - _timer = Timer.periodic(const Duration(seconds: 2), (Timer timer) { - VMHelper().updateMemoryUsage().whenComplete(() { - setState(() { - end = VMHelper().count - 1; - }); - }); - }); - }); - }); + void updateMemoryUsage() { + if (mounted) { + setState(() {}); + } } @override void dispose() { - _timer.cancel(); - VMHelper().clear(); + VMHelper().removeListener(updateMemoryUsage); super.dispose(); } - void update() {} - @override Widget build(BuildContext context) { if (VMHelper().serviceClient == null) { @@ -50,187 +37,53 @@ class _MemoryUsageViewState extends State { } final MemoryUsage main = VMHelper().mainMemoryUsage; - return Column( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - DefaultTextStyle( - style: const TextStyle(fontSize: 12, color: Colors.black), - child: Padding( + return Positioned( + top: _top, + left: _left, + child: DefaultTextStyle( + style: const TextStyle(fontSize: 12, color: Colors.black), + child: GestureDetector( + onPanUpdate: (DragUpdateDetails dragUpdateDetails) { + setState(() { + _top += dragUpdateDetails.delta.dy; + _left += dragUpdateDetails.delta.dx; + }); + }, + child: Container( + color: Colors.grey.withOpacity(0.2), padding: const EdgeInsets.all(8.0), - child: Row( + child: Column( mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, children: [ - Expanded( - child: Text.rich(TextSpan(children: [ - const TextSpan(text: 'HeapUsage: '), - TextSpan( - text: ByteUtil.toByteString(main.heapUsage!), - style: const TextStyle( - color: Colors.red, - )), - ])), - ), - Expanded( - child: Text.rich(TextSpan(children: [ - const TextSpan(text: 'HeapCapacity: '), - TextSpan( - text: ByteUtil.toByteString(main.heapCapacity!), - style: const TextStyle( - color: Colors.blue, - )), - ])), - ), - Expanded( - child: Text.rich(TextSpan(children: [ - const TextSpan(text: 'ExternalUsage: '), - TextSpan( - text: ByteUtil.toByteString(main.externalUsage!), - style: const TextStyle( - color: Colors.green, - )), - ])), - ), + Text.rich(TextSpan(children: [ + const TextSpan(text: 'HeapUsage: '), + TextSpan( + text: ByteUtil.toByteString(main.heapUsage!), + style: const TextStyle( + color: Colors.red, + )), + ])), + Text.rich(TextSpan(children: [ + const TextSpan(text: 'HeapCapacity: '), + TextSpan( + text: ByteUtil.toByteString(main.heapCapacity!), + style: const TextStyle( + color: Colors.blue, + )), + ])), + Text.rich(TextSpan(children: [ + const TextSpan(text: 'ExternalUsage: '), + TextSpan( + text: ByteUtil.toByteString(main.externalUsage!), + style: const TextStyle( + color: Colors.green, + )), + ])), ], ), ), ), - Container( - padding: - const EdgeInsets.only(left: 30, right: 30, top: 5, bottom: 5), - width: window.physicalSize.width, - height: 200, - child: LineChart( - sampleData1(), - swapAnimationDuration: const Duration(milliseconds: 250), - ), - ), - ], - ); - } - - LineChartData sampleData1() { - final DateTime now = DateTime.now(); - final List data = linesBarData1(now); - - return LineChartData( - lineTouchData: LineTouchData( - touchTooltipData: LineTouchTooltipData( - tooltipBgColor: Colors.blueGrey.withOpacity(0.8), - ), - touchCallback: (LineTouchResponse touchResponse) {}, - handleBuiltInTouches: true, - ), - gridData: FlGridData( - show: false, - ), - titlesData: FlTitlesData( - bottomTitles: SideTitles( - showTitles: true, - getTextStyles: (double value) => const TextStyle( - color: Color(0xff72719b), - fontWeight: FontWeight.bold, - fontSize: 16, - ), - margin: 10, - getTitles: (double value) { - final int millisecondsSinceEpoch = value.toInt(); - final DateTime dateTime = - DateTime.fromMillisecondsSinceEpoch(millisecondsSinceEpoch); - - return DateFormat('HH:mm').format(dateTime); - }, - interval: const Duration(minutes: 1).inMilliseconds.toDouble(), - ), - leftTitles: SideTitles( - showTitles: true, - getTextStyles: (double value) => const TextStyle( - color: Color(0xff75729e), - fontWeight: FontWeight.bold, - fontSize: 14, - ), - interval: 100, - getTitles: (double value) { - return value.toInt().toString() + 'M'; - }, - margin: 20, - ), - ), - borderData: FlBorderData( - show: true, - border: const Border( - bottom: BorderSide( - color: Color(0xff4e4965), - width: 2, - ), - left: BorderSide( - color: Color(0xff4e4965), - width: 2, - ), - right: BorderSide( - color: Colors.transparent, - ), - top: BorderSide( - color: Colors.transparent, - ), - ), - ), - minX: now - .subtract(const Duration(minutes: 1)) - .millisecondsSinceEpoch - .toDouble(), - maxX: now.millisecondsSinceEpoch.toDouble(), - minY: 0, - maxY: max(500, maxY ?? 0), - lineBarsData: data, - ); - } - - double? minY; - double? maxY; - List linesBarData1(DateTime now) { - final List data1 = []; - final List data2 = []; - final List data3 = []; - for (final MyMemoryUsage item in VMHelper().mainHistoryMemoryInfo) { - data1.add(FlSpot(item.dataTime.millisecondsSinceEpoch.toDouble(), - item.todouble(item.heapUsage))); - data2.add(FlSpot(item.dataTime.millisecondsSinceEpoch.toDouble(), - item.todouble(item.heapCapacity))); - data3.add(FlSpot(item.dataTime.millisecondsSinceEpoch.toDouble(), - item.todouble(item.externalUsage))); - - final double minValue = - min(min(item.heapUsage, item.heapCapacity), item.externalUsage); - - final double maxValue = - max(max(item.heapUsage, item.heapCapacity), item.externalUsage); - - minY = min(maxY ?? minValue.toDouble(), minValue.toDouble()); - maxY = max(maxY ?? maxValue.toDouble(), maxValue.toDouble()); - } - - return [ - getLineChartBarData(data1, Colors.red), - getLineChartBarData(data2, Colors.blue), - getLineChartBarData(data3, Colors.green), - ]; - } - - LineChartBarData getLineChartBarData(List spots, Color color) { - return LineChartBarData( - spots: spots, - isCurved: true, - colors: [ - color, - ], - barWidth: 2, - isStrokeCapRound: true, - dotData: FlDotData( - show: false, - ), - belowBarData: BarAreaData( - show: false, ), ); } diff --git a/example/lib/main.dart b/example/lib/main.dart index 3e873df5..c69a3771 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -1,4 +1,3 @@ - import 'package:extended_image/extended_image.dart'; import 'package:extended_image_library/extended_image_library.dart'; import 'package:ff_annotation_route_library/ff_annotation_route_library.dart'; @@ -6,6 +5,7 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:oktoast/oktoast.dart'; +import 'common/widget/memory_usage_view.dart'; import 'example_route.dart'; import 'example_routes.dart'; @@ -29,14 +29,21 @@ class MyApp extends StatelessWidget { primarySwatch: Colors.blue, ), builder: (BuildContext c, Widget? w) { + w = Stack( + children: [ + Positioned.fill(child: w!), + MemoryUsageView(), + ], + ); if (!kIsWeb) { final MediaQueryData data = MediaQuery.of(c); - return MediaQuery( + w = MediaQuery( data: data.copyWith(textScaleFactor: 1.0), - child: w!, + child: w, ); } - return w!; + + return w; }, initialRoute: Routes.fluttercandiesMainpage, onGenerateRoute: (RouteSettings settings) { diff --git a/example/lib/pages/complex/image_editor_demo.dart b/example/lib/pages/complex/image_editor_demo.dart index 56473631..1b0844f3 100644 --- a/example/lib/pages/complex/image_editor_demo.dart +++ b/example/lib/pages/complex/image_editor_demo.dart @@ -409,12 +409,12 @@ class _ImageEditorDemoState extends State { //await showBusyingDialog(); - Uint8List fileData; + Uint8List? fileData; /// native library if (useNative) { - fileData = Uint8List.fromList(await (cropImageDataWithNativeLibrary( - state: editorKey.currentState!) as FutureOr>)); + fileData = await cropImageDataWithNativeLibrary( + state: editorKey.currentState!); } else { ///delay due to cropImageDataWithDartLibrary is time consuming on main thread ///it will block showBusyingDialog @@ -422,11 +422,11 @@ class _ImageEditorDemoState extends State { //await Future.delayed(Duration(milliseconds: 200)); ///if you don't want to block ui, use compute/isolate,but it costs more time. - fileData = Uint8List.fromList( - await cropImageDataWithDartLibrary(state: editorKey.currentState!) ?? []) ; + fileData = + await cropImageDataWithDartLibrary(state: editorKey.currentState!); } final String? filePath = - await ImageSaver.save('extended_image_cropped_image.jpg', fileData); + await ImageSaver.save('extended_image_cropped_image.jpg', fileData!); // var filePath = await ImagePickerSaver.saveFile(fileData: fileData); msg = 'save image : $filePath'; diff --git a/example/lib/pages/complex/memory_usage_demo.dart b/example/lib/pages/complex/memory_usage_demo.dart index d1408214..26302cf7 100644 --- a/example/lib/pages/complex/memory_usage_demo.dart +++ b/example/lib/pages/complex/memory_usage_demo.dart @@ -22,7 +22,7 @@ class MemoryUsageDemo extends StatefulWidget { } class _MemoryUsageDemoState extends State { - late TuChongRepository listSourceRepository; + late TuChongRepository listSourceRepository; final String imageCacheName = 'MemoryUsage'; @override void initState() {