@@ -151,14 +151,21 @@ class ConsoleService extends Disposer {
151151 // will grow to kMaxLogItemsUpperBound then truncate to
152152 // kMaxLogItemsLowerBound.
153153 if (_stdio.value.length > kMaxLogItemsUpperBound) {
154- _stdio.trimToSublist (stdio .value.length - kMaxLogItemsLowerBound);
154+ _stdio.trimToSublist (_stdio .value.length - kMaxLogItemsLowerBound);
155155 }
156156 }
157157
158158 /// Return the stdout and stderr emitted from the application.
159159 ///
160160 /// Note that this output might be truncated after significant output.
161- ValueListenable <List <ConsoleLine >> get stdio => _stdio;
161+ ValueListenable <List <ConsoleLine >> get stdio {
162+ assert (
163+ _serviceInitialized,
164+ '`ConsoleService.ensureServiceInitialized` must be called before '
165+ 'interacting with the ConsoleService.' ,
166+ );
167+ return _stdio;
168+ }
162169
163170 void _handleStdoutEvent (Event event) {
164171 final String text = decodeBase64 (event.bytes);
@@ -174,16 +181,42 @@ class ConsoleService extends Disposer {
174181
175182 void vmServiceOpened (VmServiceWrapper service) {
176183 cancel ();
184+ // The debug stream listener must be added as soon as the service is opened
185+ // because this stream does not send event history upon the first
186+ // subscription like the streams in [ensureServiceInitialized].
177187 autoDispose (service.onDebugEvent.listen (_handleDebugEvent));
178- autoDispose (service.onStdoutEventWithHistory.listen (_handleStdoutEvent));
179- autoDispose (service.onStderrEventWithHistory.listen (_handleStderrEvent));
180- autoDispose (
181- service.onExtensionEventWithHistory.listen (_handleExtensionEvent));
182188 addAutoDisposeListener (serviceManager.isolateManager.mainIsolate, () {
183189 clearStdio ();
184190 });
185191 }
186192
193+ /// Whether the console service has been initialized.
194+ bool _serviceInitialized = false ;
195+
196+ /// Initialize the console service.
197+ ///
198+ /// Consumers of [ConsoleService] should call this method before using the
199+ /// console service in any way.
200+ ///
201+ /// These stream listeners are added here instead of in [vmServiceOpened] for
202+ /// performance reasons. Since these streams have event history, we will not
203+ /// be missing any events by listening after [vmServiceOpened] , and listening
204+ /// only when this data is needed will improve performance for connecting to
205+ /// low-end devices, as well as when DevTools pages that don't need the
206+ /// [ConsoleService] are being used.
207+ void ensureServiceInitialized () {
208+ assert (serviceManager.isServiceAvailable);
209+ if (! _serviceInitialized && serviceManager.isServiceAvailable) {
210+ autoDispose (serviceManager.service.onStdoutEventWithHistory
211+ .listen (_handleStdoutEvent));
212+ autoDispose (serviceManager.service.onStderrEventWithHistory
213+ .listen (_handleStderrEvent));
214+ autoDispose (serviceManager.service.onExtensionEventWithHistory
215+ .listen (_handleExtensionEvent));
216+ _serviceInitialized = true ;
217+ }
218+ }
219+
187220 void _handleExtensionEvent (Event e) async {
188221 if (e.extensionKind == 'Flutter.Error' ||
189222 e.extensionKind == 'Flutter.Print' ) {
@@ -210,6 +243,7 @@ class ConsoleService extends Disposer {
210243
211244 void handleVmServiceClosed () {
212245 cancel ();
246+ _serviceInitialized = false ;
213247 }
214248
215249 void _handleDebugEvent (Event event) async {
0 commit comments