import 'dart:mirrors'; import 'dart:isolate'; import 'dart:async'; /// ********************** Test ************************* /// void test() { IsolateManager.create((isoEvent, data) async { if (isoEvent == IsolateEvent.ready) { int id = data as int; IsolateManager.sendBroadcast(IsoMessege('test1')); await Future.delayed(Duration(seconds: 2)); IsolateManager.send(id, IsoMessege('test2')); IsolateManager.send(id, IsoMessege('test1')); IsolateManager.exit(id); } else if (isoEvent == IsolateEvent.exit) { print('Isolate is exited.'); } print('On Event from Isolate: ${isoEvent.name}'); }, (message) { print('On Message from Isolate: ${message.type}'); }); } class IsolateTemplate extends IsolateBase { @override void onReady() async { print('[IsolateTemplate] onReady'); addEventListener('test1', onTest1Handler, executeOnce: true); addEventListener('test2', onTest2Handler); } void onTest1Handler(Object? data) { print('[IsolateTemplate] OnTest1Handler: $data'); } void onTest2Handler(Object? data) { print('[IsolateTemplate] OnTest2Handler: $data'); } } /// ********************** Define *********************** /// enum IsolateEvent { ready, exit } class IsoMessege { late String type; late Object? message; IsoMessege(this.type, {this.message}); } class _IsolateInnerEvent { static const String ready = '_IsolateInnerEvent.Ready'; static const String exit = '_IsolateInnerEvent.Exit'; } class _IsolateConstructData { late int id; late SendPort mainIsoSender; _IsolateConstructData(this.id, this.mainIsoSender); } class IsolateManager { IsolateManager._privateConstructor(); static final IsolateManager _instance = IsolateManager._privateConstructor(); static IsolateManager get to => _instance; int _nonce = 0; int get nonce { if (_nonce == double.maxFinite.toInt()) { _nonce = 0; } else { _nonce++; } return _nonce; } final Map _isoMap = {}; final Map> _innerEventMap = {}; static void create( Function(IsolateEvent, Object?) isolateEventListener, Function(IsoMessege) messageListener) async { to._create(isolateEventListener, messageListener); } void _create( Function(IsolateEvent, Object?) isolateEventListener, Function(IsoMessege) messageListener) async { final isoListener = ReceivePort(); var id = nonce; T inst = Activator.createInstance(T, {}); _isoMap[id] = inst; _addInnerEvent(id, _IsolateInnerEvent.ready, (message) { inst.isoListener = message as SendPort; isolateEventListener(IsolateEvent.ready, id); }); await Isolate.spawn( inst.initialize, _IsolateConstructData(id, isoListener.sendPort)); await for (IsoMessege message in isoListener) { if (message.type == _IsolateInnerEvent.exit) { isolateEventListener(IsolateEvent.exit, null); break; } else if (_filterInnerEvent(id, message)) { messageListener(message); } } isoListener.close(); _isoMap.remove(id); } void _addInnerEvent(int id, String type, Function(Object?) listener) { Map? eventMap; if (!_innerEventMap.containsKey(id)) { eventMap = {}; _innerEventMap[id] = eventMap; } eventMap![type] = listener; } bool _filterInnerEvent(int id, IsoMessege message) { var isNotExist = true; if (_innerEventMap.containsKey(id) && _innerEventMap[id]!.containsKey(message.type)) { isNotExist = false; _innerEventMap[id]![message.type]!(message.message); } return isNotExist; } static void sendBroadcast(IsoMessege message) { var entries = to._isoMap.entries; for (var entry in entries) { entry.value.insertEvent(message); } } static void send(int id, IsoMessege message) { var map = to._isoMap; if (map.containsKey(id)) { map[id]?.insertEvent(message); } } static void exit(int id) { var map = to._isoMap; if (map.containsKey(id)) { map[id]!.insertEvent(IsoMessege(_IsolateInnerEvent.exit)); } } } class _IsolateEventListener { late bool executeOnce; late Function(Object?) listener; _IsolateEventListener(this.listener, this.executeOnce); } class IsolateBase { late int id; late ReceivePort _mainIsoListener; late SendPort _mainIsoSender; late SendPort isoListener; final Map> _eventMap = {}; final List<_IsolateEventListener> _removeList = []; // ignore: library_private_types_in_public_api Future initialize(_IsolateConstructData initData) async { id = initData.id; _mainIsoListener = ReceivePort(); _mainIsoSender = initData.mainIsoSender; send(IsoMessege(_IsolateInnerEvent.ready, message: _mainIsoListener.sendPort)); onReady(); await for (IsoMessege message in _mainIsoListener) { if (message.type == _IsolateInnerEvent.exit) { send(IsoMessege(_IsolateInnerEvent.exit)); break; } else { _onEvent(message); } } Isolate.exit(_mainIsoSender); } void onReady() async {} void send(IsoMessege message) { _mainIsoSender.send(message); } void _onEvent(IsoMessege message) { if (_eventMap.containsKey(message.type)) { var list = _eventMap[message.type]!; for (var item in list) { item.listener(message.message); if (item.executeOnce) { _removeList.add(item); } } if (_removeList.isNotEmpty) { for (var item in _removeList) { removeEventListener(message.type, item.listener); } _removeList.clear(); } } } void addEventListener(String type, Function(Object?) listener, {bool executeOnce = true}) { List<_IsolateEventListener> list; if (_eventMap.containsKey(type)) { list = _eventMap[type]!; } else { list = []; _eventMap[type] = list; } list.add(_IsolateEventListener(listener, executeOnce)); } void removeEventListener(String type, Function(Object?) listener) { if (_eventMap.containsKey(type)) { var list = _eventMap[type]!; for (int i = 0; i < list.length; ++i) { var item = list[i]; if (item.listener == listener) { list.removeAt(i); --i; } } } } void insertEvent(IsoMessege message) { isoListener.send(message); } } class Activator { static createInstance(Type type, Map namedArguments, [Symbol? constructor, List? arguments]) { constructor ??= const Symbol(""); arguments ??= const []; var typeMirror = reflectType(type); if (typeMirror is ClassMirror) { return typeMirror .newInstance(constructor, arguments, namedArguments) .reflectee; } else { throw ArgumentError("Cannot create the instance of the type '$type'."); } } }