Fix Network tab not capturing requests after hot restart and clear (#9856)

* Fix Network tab not capturing requests after hot restart and clear.

Re-enable HTTP logging and socket profiling when new isolates are spawned,
reset clear timestamps using the VM timeline, and keep the search field
enabled while recording.

* Add PR links to Network profiler release notes.

* Address review feedback for Network tab lifecycle fixes.

Keep search enabled when paused with visible requests, handle RPC errors
during clear, and wrap isolate profiling re-enable in allowedError.

* Update copyright year to 2026 and refactor timestamp values in network tests for clarity. Adjusted start times in various test cases and improved code readability in the HotRestartNetworkVmService class.

* docs: remove redundant release note for Network tab

* Address review feedback for Network tab lifecycle fixes.

Use VM timeline timestamps in updateLastHttpDataRefreshTime, restore
clearData helpers and the profiling TODO, and keep the Network search
field always enabled.
diff --git a/packages/devtools_app/lib/src/screens/network/network_controller.dart b/packages/devtools_app/lib/src/screens/network/network_controller.dart
index dfb9a90..086703f 100644
--- a/packages/devtools_app/lib/src/screens/network/network_controller.dart
+++ b/packages/devtools_app/lib/src/screens/network/network_controller.dart
@@ -192,6 +192,15 @@
       _currentNetworkRequests,
       _filterAndRefreshSearchMatches,
     );
+    autoDisposeStreamSubscription(
+      serviceConnection.serviceManager.isolateManager.onIsolateCreated.listen((
+        _,
+      ) async {
+        if (_recordingNotifier.value) {
+          await allowedError(_enableNetworkTrafficRecordingOnAllIsolates());
+        }
+      }),
+    );
   }
 
   @override
@@ -327,7 +336,7 @@
     // Cancel existing polling timer before starting recording.
     _updatePollingState(false);
 
-    networkService.updateLastHttpDataRefreshTime(
+    await networkService.updateLastHttpDataRefreshTime(
       alreadyRecordingHttp: alreadyRecordingHttp,
     );
     final timestamp = await networkService.updateLastSocketDataRefreshTime(
@@ -352,11 +361,16 @@
 
     // TODO(kenz): only call these if http logging and socket profiling are not
     // already enabled. Listen to service manager streams for this info.
+    await _enableNetworkTrafficRecordingOnAllIsolates();
+    await togglePolling(true);
+  }
+
+  /// Enables HTTP timeline logging and socket profiling on all isolates.
+  Future<void> _enableNetworkTrafficRecordingOnAllIsolates() async {
     await [
       http_service.toggleHttpRequestLogging(true),
       networkService.toggleSocketProfiling(true),
     ].wait;
-    await togglePolling(true);
   }
 
   Future<void> stopRecording() async {
@@ -382,7 +396,7 @@
   /// This will ensure that future fetches for http and socket requests will at
   /// most fetch requests since [updateLastRefreshTime] was called.
   Future<void> updateLastRefreshTime() async {
-    networkService.updateLastHttpDataRefreshTime();
+    await networkService.updateLastHttpDataRefreshTime();
     await networkService.updateLastSocketDataRefreshTime();
   }
 
diff --git a/packages/devtools_app/lib/src/screens/network/network_service.dart b/packages/devtools_app/lib/src/screens/network/network_service.dart
index a93f35d..59fbb64 100644
--- a/packages/devtools_app/lib/src/screens/network/network_service.dart
+++ b/packages/devtools_app/lib/src/screens/network/network_service.dart
@@ -14,8 +14,11 @@
   NetworkController get networkController =>
       screenControllers.lookup<NetworkController>();
 
-  /// Tracks the time (microseconds since epoch) that the HTTP profile was last
-  /// retrieved for a given isolate ID.
+  /// Tracks the VM timeline timestamp (microseconds) that the HTTP profile was
+  /// last retrieved for a given isolate ID.
+  ///
+  /// These values are passed to `getHttpProfile` as `updatedSince`, which must
+  /// use the VM's monotonic timeline clock — not wall-clock time.
   final lastHttpDataRefreshTimePerIsolate = <String, int>{};
 
   /// Updates the last Socket data refresh time to the current time.
@@ -41,21 +44,25 @@
     return timestamp;
   }
 
-  /// Updates the last HTTP data refresh time to the current time.
+  /// Updates the last HTTP data refresh time to the current VM timeline time.
   ///
   /// If [alreadyRecordingHttp] is true it's unclear when the last refresh time
   /// would have occurred, so the refresh time is not updated. Otherwise,
-  /// [lastHttpDataRefreshTimePerIsolate] is updated to the current
-  /// time.
-  void updateLastHttpDataRefreshTime({bool alreadyRecordingHttp = false}) {
+  /// [lastHttpDataRefreshTimePerIsolate] is updated to the current VM timeline
+  /// timestamp for each known isolate.
+  ///
+  /// Wall-clock time must not be used here: `getHttpProfile`'s `updatedSince`
+  /// expects the VM timeline clock. A wall-clock value would filter out all
+  /// subsequent requests.
+  Future<void> updateLastHttpDataRefreshTime({
+    bool alreadyRecordingHttp = false,
+  }) async {
     if (!alreadyRecordingHttp) {
+      final service = serviceConnection.serviceManager.service;
+      if (service == null) return;
+      final timestamp = (await service.getVMTimelineMicros()).timestamp!;
       for (final isolateId in lastHttpDataRefreshTimePerIsolate.keys.toList()) {
-        // It's safe to use `DateTime.now()` here since we don't need to worry
-        // about dropping data between the time the last profile was generated
-        // by the target application and the time `DateTime.now()` is called
-        // here.
-        lastHttpDataRefreshTimePerIsolate[isolateId] =
-            DateTime.now().microsecondsSinceEpoch;
+        lastHttpDataRefreshTimePerIsolate[isolateId] = timestamp;
       }
     }
   }
@@ -202,9 +209,15 @@
   }
 
   Future<void> clearData() async {
-    await updateLastSocketDataRefreshTime();
-    updateLastHttpDataRefreshTime();
-    await _clearSocketProfile();
-    await _clearHttpProfile();
+    try {
+      await updateLastSocketDataRefreshTime();
+      await updateLastHttpDataRefreshTime();
+      await _clearSocketProfile();
+      await _clearHttpProfile();
+    } on RPCError catch (e) {
+      if (!e.isServiceDisposedError) {
+        rethrow;
+      }
+    }
   }
 }
diff --git a/packages/devtools_app/release_notes/NEXT_RELEASE_NOTES.md b/packages/devtools_app/release_notes/NEXT_RELEASE_NOTES.md
index 0d7aeb8..998ed94 100644
--- a/packages/devtools_app/release_notes/NEXT_RELEASE_NOTES.md
+++ b/packages/devtools_app/release_notes/NEXT_RELEASE_NOTES.md
@@ -53,8 +53,12 @@
 
 ## Network profiler updates
 
-* Fixed exported response status in HAR files so that they parse as integers
-  instead of strings. [#9900](https://github.com/flutter/devtools/pull/9900)
+* Fixed an issue where the Network tab would stop capturing HTTP requests after
+  a hot restart. -
+  [#9856](https://github.com/flutter/devtools/pull/9856)
+* Fixed an issue where the Network tab would stop capturing new HTTP requests
+  after pressing Clear while recording. -
+  [#9856](https://github.com/flutter/devtools/pull/9856)
 
 ## Logging updates
 
diff --git a/packages/devtools_app/test/screens/network/network_clear_test.dart b/packages/devtools_app/test/screens/network/network_clear_test.dart
new file mode 100644
index 0000000..b53140c
--- /dev/null
+++ b/packages/devtools_app/test/screens/network/network_clear_test.dart
@@ -0,0 +1,313 @@
+// Copyright 2026 The Flutter Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file or at https://developers.google.com/open-source/licenses/bsd.
+
+@TestOn('vm')
+library;
+
+import 'package:devtools_app/devtools_app.dart';
+import 'package:devtools_test/devtools_test.dart';
+import 'package:flutter_test/flutter_test.dart';
+
+import 'utils/hot_restart_network_vm_service.dart';
+import 'utils/network_lifecycle_test_utils.dart';
+import 'utils/network_test_utils.dart';
+
+void main() {
+  group('Network View clear button', () {
+    late HotRestartNetworkVmService vmService;
+    late FakeServiceConnectionManager fakeServiceConnection;
+
+    setUp(() {
+      vmService = HotRestartNetworkVmService();
+      fakeServiceConnection = FakeServiceConnectionManager(service: vmService);
+    });
+
+    tearDown(disposeNetworkLifecycleControllers);
+
+    group('request visibility after clear', () {
+      test('displays new HTTP requests after clear while recording', () async {
+        final isolateId = vmService.currentIsolateId;
+        final controller = await initNetworkLifecycleController(
+          vmService: vmService,
+          fakeServiceConnection: fakeServiceConnection,
+          initialProfile: [
+            createTestHttpRequest(id: 'before-clear', method: 'GET'),
+          ],
+        );
+        await controller.networkService.refreshNetworkData();
+        expect(controller.requests.value, hasLength(1));
+
+        await controller.clear();
+        expect(controller.requests.value, isEmpty);
+
+        vmService.appendHttpRequest(
+          isolateId,
+          createTestHttpRequest(id: 'after-clear', method: 'POST'),
+        );
+        await controller.networkService.refreshNetworkData();
+
+        expect(
+          controller.requests.value.whereType<DartIOHttpRequestData>().map(
+            (request) => request.method,
+          ),
+          contains('POST'),
+          reason:
+              'Network View should display new requests after Clear while '
+              'recording is active.',
+        );
+      });
+
+      test('polling remains active after clear', () async {
+        final controller = await initNetworkLifecycleController(
+          vmService: vmService,
+          fakeServiceConnection: fakeServiceConnection,
+          initialProfile: [
+            createTestHttpRequest(id: 'polling-test', method: 'GET'),
+          ],
+        );
+        await controller.networkService.refreshNetworkData();
+
+        await controller.clear();
+
+        expect(controller.isPolling, isTrue);
+        expect(controller.recordingNotifier.value, isTrue);
+      });
+
+      test('keeps HTTP logging enabled after clear', () async {
+        final isolateId = vmService.currentIsolateId;
+        final controller = await initNetworkLifecycleController(
+          vmService: vmService,
+          fakeServiceConnection: fakeServiceConnection,
+          initialProfile: [
+            createTestHttpRequest(id: 'logging-test', method: 'GET'),
+          ],
+        );
+        await controller.networkService.refreshNetworkData();
+
+        await controller.clear();
+
+        expect(vmService.isHttpLoggingEnabled(isolateId), isTrue);
+      });
+
+      test('keeps socket profiling enabled after clear', () async {
+        final isolateId = vmService.currentIsolateId;
+        final controller = await initNetworkLifecycleController(
+          vmService: vmService,
+          fakeServiceConnection: fakeServiceConnection,
+          initialProfile: [
+            createTestHttpRequest(id: 'socket-test', method: 'GET'),
+          ],
+        );
+        await controller.networkService.refreshNetworkData();
+
+        await controller.clear();
+
+        expect(vmService.isSocketProfilingEnabled(isolateId), isTrue);
+      });
+    });
+
+    group('clear refresh timestamp tracking', () {
+      test(
+        'resets HTTP refresh timestamps to the VM timeline on clear',
+        () async {
+          final isolateId = vmService.currentIsolateId;
+          final controller = await initNetworkLifecycleController(
+            vmService: vmService,
+            fakeServiceConnection: fakeServiceConnection,
+          );
+          await controller.networkService.refreshNetworkData();
+
+          controller
+                  .networkService
+                  .lastHttpDataRefreshTimePerIsolate[isolateId] =
+              500_000;
+
+          await controller.clear();
+
+          final timelineMicros =
+              (await vmService.getVMTimelineMicros()).timestamp!;
+          expect(
+            controller
+                .networkService
+                .lastHttpDataRefreshTimePerIsolate[isolateId],
+            timelineMicros,
+          );
+          expect(controller.lastSocketDataRefreshMicros, timelineMicros);
+        },
+      );
+
+      test('does not show stale requests after clear', () async {
+        final controller = await initNetworkLifecycleController(
+          vmService: vmService,
+          fakeServiceConnection: fakeServiceConnection,
+          initialProfile: [
+            createTestHttpRequest(
+              id: 'stale-request',
+              method: 'GET',
+              startTime: 1_500_000,
+            ),
+          ],
+        );
+        await controller.networkService.refreshNetworkData();
+        expect(controller.requests.value, hasLength(1));
+
+        await controller.clear();
+        await controller.networkService.refreshNetworkData();
+
+        expect(controller.requests.value, isEmpty);
+      });
+    });
+
+    group('clear combined with hot restart', () {
+      test('clear then hot restart then new requests', () async {
+        final controller = await initNetworkLifecycleController(
+          vmService: vmService,
+          fakeServiceConnection: fakeServiceConnection,
+          initialProfile: [
+            createTestHttpRequest(id: 'pre-clear', method: 'GET'),
+          ],
+        );
+        await controller.networkService.refreshNetworkData();
+        await controller.clear();
+
+        final postRestartIsolateId = vmService.simulateHotRestart();
+        notifyMainIsolateChanged(fakeServiceConnection, postRestartIsolateId);
+        await pumpEventQueue();
+
+        vmService.appendHttpRequest(
+          postRestartIsolateId,
+          createTestHttpRequest(
+            id: 'after-clear-and-restart',
+            method: 'PUT',
+            startTime: 9_000_000,
+          ),
+        );
+        await controller.networkService.refreshNetworkData();
+
+        expect(
+          controller.requests.value.whereType<DartIOHttpRequestData>().map(
+            (request) => request.method,
+          ),
+          contains('PUT'),
+        );
+        expect(vmService.isHttpLoggingEnabled(postRestartIsolateId), isTrue);
+      });
+
+      test('hot restart then clear then new requests', () async {
+        final controller = await initNetworkLifecycleController(
+          vmService: vmService,
+          fakeServiceConnection: fakeServiceConnection,
+          initialProfile: [
+            createTestHttpRequest(id: 'pre-restart', method: 'GET'),
+          ],
+        );
+        await controller.networkService.refreshNetworkData();
+
+        final postRestartIsolateId = vmService.simulateHotRestart();
+        notifyMainIsolateChanged(fakeServiceConnection, postRestartIsolateId);
+        await pumpEventQueue();
+        vmService.appendHttpRequest(
+          postRestartIsolateId,
+          createTestHttpRequest(
+            id: 'after-restart',
+            method: 'POST',
+            startTime: 8_000_000,
+          ),
+        );
+        await controller.networkService.refreshNetworkData();
+        expect(controller.requests.value, isNotEmpty);
+
+        await controller.clear();
+        expect(controller.requests.value, isEmpty);
+
+        vmService.appendHttpRequest(
+          postRestartIsolateId,
+          createTestHttpRequest(
+            id: 'after-restart-and-clear',
+            method: 'DELETE',
+            startTime: 10_000_000,
+          ),
+        );
+        await controller.networkService.refreshNetworkData();
+
+        expect(
+          controller.requests.value.whereType<DartIOHttpRequestData>().map(
+            (request) => request.method,
+          ),
+          contains('DELETE'),
+        );
+      });
+    });
+
+    group('state after clear', () {
+      test('clears selected request', () async {
+        final controller = await initNetworkLifecycleController(
+          vmService: vmService,
+          fakeServiceConnection: fakeServiceConnection,
+          initialProfile: [
+            createTestHttpRequest(id: 'selected', method: 'GET'),
+          ],
+        );
+        await controller.networkService.refreshNetworkData();
+        controller.selectedRequest.value = controller.requests.value.first;
+
+        await controller.clear();
+
+        expect(controller.selectedRequest.value, isNull);
+      });
+
+      test('preserves active search text', () async {
+        final controller = await initNetworkLifecycleController(
+          vmService: vmService,
+          fakeServiceConnection: fakeServiceConnection,
+          initialProfile: [
+            createTestHttpRequest(
+              id: 'searchable',
+              method: 'GET',
+              uri: 'https://example.com/api',
+            ),
+          ],
+        );
+        await controller.networkService.refreshNetworkData();
+        controller.search = 'example';
+
+        await controller.clear();
+
+        expect(controller.search, 'example');
+      });
+
+      test('supports multiple consecutive clears', () async {
+        final isolateId = vmService.currentIsolateId;
+        final controller = await initNetworkLifecycleController(
+          vmService: vmService,
+          fakeServiceConnection: fakeServiceConnection,
+          initialProfile: [
+            createTestHttpRequest(id: 'multi-clear-1', method: 'GET'),
+          ],
+        );
+        await controller.networkService.refreshNetworkData();
+
+        await controller.clear();
+        await controller.clear();
+
+        vmService.appendHttpRequest(
+          isolateId,
+          createTestHttpRequest(
+            id: 'after-multi-clear',
+            method: 'PATCH',
+            startTime: 3_000_000,
+          ),
+        );
+        await controller.networkService.refreshNetworkData();
+
+        expect(
+          controller.requests.value.whereType<DartIOHttpRequestData>().map(
+            (request) => request.method,
+          ),
+          contains('PATCH'),
+        );
+      });
+    });
+  });
+}
diff --git a/packages/devtools_app/test/screens/network/network_hot_restart_test.dart b/packages/devtools_app/test/screens/network/network_hot_restart_test.dart
new file mode 100644
index 0000000..cbf9cd6
--- /dev/null
+++ b/packages/devtools_app/test/screens/network/network_hot_restart_test.dart
@@ -0,0 +1,456 @@
+// Copyright 2026 The Flutter Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file or at https://developers.google.com/open-source/licenses/bsd.
+
+@TestOn('vm')
+library;
+
+import 'package:devtools_app/devtools_app.dart';
+import 'package:devtools_test/devtools_test.dart';
+import 'package:flutter_test/flutter_test.dart';
+
+import 'utils/hot_restart_network_vm_service.dart';
+import 'utils/network_lifecycle_test_utils.dart';
+import 'utils/network_test_utils.dart';
+
+void main() {
+  group('Network View hot restart', () {
+    late HotRestartNetworkVmService vmService;
+    late FakeServiceConnectionManager fakeServiceConnection;
+
+    setUp(() {
+      vmService = HotRestartNetworkVmService();
+      fakeServiceConnection = FakeServiceConnectionManager(service: vmService);
+    });
+
+    tearDown(disposeNetworkLifecycleControllers);
+
+    group('baseline behavior before hot restart', () {
+      test('displays HTTP requests after recording starts', () async {
+        final controller = await initNetworkLifecycleController(
+          vmService: vmService,
+          fakeServiceConnection: fakeServiceConnection,
+          initialProfile: [
+            createTestHttpRequest(id: 'pre-restart-1', method: 'GET'),
+          ],
+        );
+
+        expect(
+          vmService.isHttpLoggingEnabled(vmService.currentIsolateId),
+          isTrue,
+        );
+        await controller.networkService.refreshNetworkData();
+
+        expect(controller.requests.value, hasLength(1));
+        expect(
+          controller.requests.value.single,
+          isA<DartIOHttpRequestData>().having(
+            (request) => request.method,
+            'method',
+            'GET',
+          ),
+        );
+      });
+
+      test('continues polling while connected', () async {
+        final controller = await initNetworkLifecycleController(
+          vmService: vmService,
+          fakeServiceConnection: fakeServiceConnection,
+        );
+        expect(controller.isPolling, isTrue);
+        expect(controller.recordingNotifier.value, isTrue);
+      });
+    });
+
+    group('hot restart request visibility', () {
+      test(
+        'continues displaying new HTTP requests after hot restart',
+        () async {
+          final controller = await initNetworkLifecycleController(
+            vmService: vmService,
+            fakeServiceConnection: fakeServiceConnection,
+            initialProfile: [
+              createTestHttpRequest(id: 'pre-restart', method: 'GET'),
+            ],
+          );
+          await controller.networkService.refreshNetworkData();
+          expect(controller.requests.value, hasLength(1));
+
+          final postRestartIsolateId = vmService.simulateHotRestart();
+          notifyMainIsolateChanged(fakeServiceConnection, postRestartIsolateId);
+          await pumpEventQueue();
+          vmService.setHttpProfile(postRestartIsolateId, [
+            createTestHttpRequest(
+              id: 'post-restart',
+              method: 'POST',
+              startTime: 8_000_000,
+            ),
+          ]);
+
+          await controller.networkService.refreshNetworkData();
+
+          final methods = controller.requests.value
+              .whereType<DartIOHttpRequestData>()
+              .map((request) => request.method)
+              .toSet();
+          expect(
+            methods,
+            contains('POST'),
+            reason:
+                'Network View should display requests made on the new isolate '
+                'after a hot restart.',
+          );
+        },
+      );
+
+      test('polling remains active after hot restart', () async {
+        final controller = await initNetworkLifecycleController(
+          vmService: vmService,
+          fakeServiceConnection: fakeServiceConnection,
+        );
+        expect(controller.isPolling, isTrue);
+
+        final postRestartIsolateId = vmService.simulateHotRestart();
+        notifyMainIsolateChanged(fakeServiceConnection, postRestartIsolateId);
+
+        expect(controller.isPolling, isTrue);
+        expect(controller.recordingNotifier.value, isTrue);
+      });
+    });
+
+    group('profiling re-registration after hot restart', () {
+      test(
+        're-enables HTTP timeline logging on the new isolate after hot restart',
+        () async {
+          final preRestartIsolateId = vmService.currentIsolateId;
+          await initNetworkLifecycleController(
+            vmService: vmService,
+            fakeServiceConnection: fakeServiceConnection,
+          );
+          expect(vmService.isHttpLoggingEnabled(preRestartIsolateId), isTrue);
+
+          final postRestartIsolateId = vmService.simulateHotRestart();
+          notifyMainIsolateChanged(fakeServiceConnection, postRestartIsolateId);
+          await pumpEventQueue();
+
+          expect(
+            vmService.isHttpLoggingEnabled(postRestartIsolateId),
+            isTrue,
+            reason:
+                'HTTP timeline logging must be re-enabled on the new main '
+                'isolate after a hot restart.',
+          );
+        },
+      );
+
+      test(
+        're-enables socket profiling on the new isolate after hot restart',
+        () async {
+          final preRestartIsolateId = vmService.currentIsolateId;
+          await initNetworkLifecycleController(
+            vmService: vmService,
+            fakeServiceConnection: fakeServiceConnection,
+          );
+          expect(
+            vmService.isSocketProfilingEnabled(preRestartIsolateId),
+            isTrue,
+          );
+
+          final postRestartIsolateId = vmService.simulateHotRestart();
+          notifyMainIsolateChanged(fakeServiceConnection, postRestartIsolateId);
+          await pumpEventQueue();
+
+          expect(
+            vmService.isSocketProfilingEnabled(postRestartIsolateId),
+            isTrue,
+            reason:
+                'Socket profiling must be re-enabled on the new main isolate '
+                'after a hot restart.',
+          );
+        },
+      );
+    });
+
+    group('isolate refresh timestamp tracking', () {
+      test(
+        'fetches HTTP profile data for a new isolate after profiling is re-enabled',
+        () async {
+          final controller = await initNetworkLifecycleController(
+            vmService: vmService,
+            fakeServiceConnection: fakeServiceConnection,
+          );
+          await controller.networkService.refreshNetworkData();
+
+          final postRestartIsolateId = vmService.simulateHotRestart();
+          notifyMainIsolateChanged(fakeServiceConnection, postRestartIsolateId);
+          vmService.setHttpProfile(postRestartIsolateId, [
+            createTestHttpRequest(
+              id: 'new-isolate-request',
+              method: 'PUT',
+              startTime: 9_000_000,
+            ),
+          ]);
+
+          await pumpEventQueue();
+          await controller.networkService.refreshNetworkData();
+
+          expect(
+            controller.networkService.lastHttpDataRefreshTimePerIsolate
+                .containsKey(postRestartIsolateId),
+            isTrue,
+            reason:
+                'NetworkService should track refresh timestamps for the new '
+                'isolate after a hot restart.',
+          );
+          expect(
+            controller.requests.value.whereType<DartIOHttpRequestData>().map(
+              (request) => request.method,
+            ),
+            contains('PUT'),
+          );
+        },
+      );
+
+      test(
+        'stale isolate IDs do not prevent fetching from the new isolate',
+        () async {
+          final preRestartIsolateId = vmService.currentIsolateId;
+          final controller = await initNetworkLifecycleController(
+            vmService: vmService,
+            fakeServiceConnection: fakeServiceConnection,
+          );
+          await controller.networkService.refreshNetworkData();
+
+          controller
+                  .networkService
+                  .lastHttpDataRefreshTimePerIsolate[preRestartIsolateId] =
+              12_000_000;
+
+          final postRestartIsolateId = vmService.simulateHotRestart();
+          notifyMainIsolateChanged(fakeServiceConnection, postRestartIsolateId);
+          vmService.setHttpProfile(postRestartIsolateId, [
+            createTestHttpRequest(
+              id: 'after-stale-isolate',
+              method: 'DELETE',
+              startTime: 10_000_000,
+            ),
+          ]);
+          await pumpEventQueue();
+          await controller.networkService.refreshNetworkData();
+
+          expect(
+            controller.requests.value.whereType<DartIOHttpRequestData>().map(
+              (request) => request.method,
+            ),
+            contains('DELETE'),
+          );
+        },
+      );
+    });
+
+    group('state restoration across hot restart', () {
+      test('retains pre-restart requests when not cleared', () async {
+        final controller = await initNetworkLifecycleController(
+          vmService: vmService,
+          fakeServiceConnection: fakeServiceConnection,
+          initialProfile: [
+            createTestHttpRequest(id: 'kept-request', method: 'GET'),
+          ],
+        );
+        await controller.networkService.refreshNetworkData();
+        expect(controller.requests.value, hasLength(1));
+
+        final postRestartIsolateId = vmService.simulateHotRestart();
+        notifyMainIsolateChanged(fakeServiceConnection, postRestartIsolateId);
+        vmService.setHttpProfile(postRestartIsolateId, [
+          createTestHttpRequest(
+            id: 'new-request',
+            method: 'POST',
+            startTime: 11_000_000,
+          ),
+        ]);
+        await pumpEventQueue();
+        await controller.networkService.refreshNetworkData();
+
+        final methods = controller.requests.value
+            .whereType<DartIOHttpRequestData>()
+            .map((request) => request.method)
+            .toList();
+        expect(methods, contains('GET'));
+        expect(methods, contains('POST'));
+      });
+
+      test(
+        'clears selected request when it is no longer in filtered data',
+        () async {
+          final controller = await initNetworkLifecycleController(
+            vmService: vmService,
+            fakeServiceConnection: fakeServiceConnection,
+            initialProfile: [
+              createTestHttpRequest(id: 'selected-request', method: 'GET'),
+            ],
+          );
+          await controller.networkService.refreshNetworkData();
+          controller.selectedRequest.value = controller.requests.value.first;
+
+          await controller.clear();
+          expect(controller.selectedRequest.value, isNull);
+        },
+      );
+    });
+  });
+
+  group('Network View service lifecycle', () {
+    tearDown(disposeNetworkLifecycleControllers);
+
+    test(
+      'starts recording when controller initializes while connected',
+      () async {
+        final reconnectionService = HotRestartNetworkVmService();
+        final connection = FakeServiceConnectionManager(
+          service: reconnectionService,
+        );
+        final reconnectedController = await initNetworkLifecycleController(
+          vmService: reconnectionService,
+          fakeServiceConnection: connection,
+        );
+
+        expect(reconnectedController.isPolling, isTrue);
+        expect(
+          reconnectionService.isHttpLoggingEnabled(
+            reconnectionService.currentIsolateId,
+          ),
+          isTrue,
+        );
+      },
+    );
+
+    test(
+      're-initializes recording after controller is disposed and recreated',
+      () async {
+        final vmService = HotRestartNetworkVmService();
+        final connection = FakeServiceConnectionManager(service: vmService);
+        final isolateId = vmService.currentIsolateId;
+        await initNetworkLifecycleController(
+          vmService: vmService,
+          fakeServiceConnection: connection,
+        );
+
+        screenControllers.disposeConnectedControllers();
+
+        final recreatedController = await initNetworkLifecycleController(
+          vmService: vmService,
+          fakeServiceConnection: connection,
+        );
+
+        expect(recreatedController.isPolling, isTrue);
+        expect(vmService.isHttpLoggingEnabled(isolateId), isTrue);
+      },
+    );
+  });
+
+  group('NetworkService hot restart edge cases', () {
+    tearDown(disposeNetworkLifecycleControllers);
+
+    test(
+      'refreshNetworkData is a no-op when the VM service is unavailable',
+      () async {
+        final localVmService = HotRestartNetworkVmService();
+        final localConnection = FakeServiceConnectionManager(
+          service: localVmService,
+        );
+        final localController = await initNetworkLifecycleController(
+          vmService: localVmService,
+          fakeServiceConnection: localConnection,
+        );
+
+        localConnection.serviceManager.service = null;
+        await expectLater(
+          localController.networkService.refreshNetworkData(),
+          completes,
+        );
+        expect(localController.requests.value, isEmpty);
+      },
+    );
+
+    test(
+      'updateLastHttpDataRefreshTime does not add entries for new isolates',
+      () async {
+        final localVmService = HotRestartNetworkVmService();
+        final localConnection = FakeServiceConnectionManager(
+          service: localVmService,
+        );
+        final localController = await initNetworkLifecycleController(
+          vmService: localVmService,
+          fakeServiceConnection: localConnection,
+        );
+
+        final postRestartIsolateId = localVmService.simulateHotRestart();
+        await localController.networkService.updateLastHttpDataRefreshTime();
+
+        expect(
+          localController.networkService.lastHttpDataRefreshTimePerIsolate
+              .containsKey(postRestartIsolateId),
+          isFalse,
+          reason:
+              'updateLastHttpDataRefreshTime only updates existing isolate '
+              'entries; new isolates are registered on the first profile fetch.',
+        );
+      },
+    );
+
+    test(
+      'pause then resume uses VM timeline for HTTP refresh timestamps',
+      () async {
+        final localVmService = HotRestartNetworkVmService();
+        final localConnection = FakeServiceConnectionManager(
+          service: localVmService,
+        );
+        final isolateId = localVmService.currentIsolateId;
+        final controller = await initNetworkLifecycleController(
+          vmService: localVmService,
+          fakeServiceConnection: localConnection,
+          initialProfile: [
+            createTestHttpRequest(id: 'before-pause', method: 'GET'),
+          ],
+        );
+        await controller.networkService.refreshNetworkData();
+        expect(
+          controller.networkService.lastHttpDataRefreshTimePerIsolate
+              .containsKey(isolateId),
+          isTrue,
+        );
+
+        await controller.togglePolling(false);
+        await controller.togglePolling(true);
+
+        final timelineMicros =
+            (await localVmService.getVMTimelineMicros()).timestamp!;
+        expect(
+          controller
+              .networkService
+              .lastHttpDataRefreshTimePerIsolate[isolateId],
+          timelineMicros,
+          reason:
+              'Resuming recording must stamp HTTP refresh times with the VM '
+              'timeline clock, not wall-clock time.',
+        );
+        expect(controller.lastSocketDataRefreshMicros, timelineMicros);
+
+        localVmService.appendHttpRequest(
+          isolateId,
+          createTestHttpRequest(
+            id: 'after-resume',
+            method: 'POST',
+            startTime: timelineMicros + 1_000,
+          ),
+        );
+        await controller.networkService.refreshNetworkData();
+        expect(
+          controller.requests.value.map((r) => r.id),
+          contains('after-resume'),
+        );
+      },
+    );
+  });
+}
diff --git a/packages/devtools_app/test/screens/network/utils/hot_restart_network_vm_service.dart b/packages/devtools_app/test/screens/network/utils/hot_restart_network_vm_service.dart
new file mode 100644
index 0000000..5403dc7
--- /dev/null
+++ b/packages/devtools_app/test/screens/network/utils/hot_restart_network_vm_service.dart
@@ -0,0 +1,191 @@
+// Copyright 2026 The Flutter Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file or at https://developers.google.com/open-source/licenses/bsd.
+
+import 'package:devtools_app/devtools_app.dart';
+import 'package:devtools_test/devtools_test.dart';
+import 'package:vm_service/vm_service.dart';
+
+/// A fake VM service that models hot-restart isolate lifecycle for Network View
+/// tests.
+///
+/// After a hot restart, the VM spawns a new main isolate whose HTTP timeline
+/// logging and socket profiling are disabled until explicitly re-enabled.
+/// [getHttpProfileWrapper] and [getSocketProfileWrapper] return empty data when
+/// profiling is disabled for an isolate, matching real VM behavior.
+class HotRestartNetworkVmService extends FakeVmServiceWrapper {
+  HotRestartNetworkVmService()
+    : super(
+        _testVmFlagManager,
+        null,
+        null,
+        SocketProfile(sockets: []),
+        HttpProfile(
+          requests: [],
+          timestamp: DateTime.fromMicrosecondsSinceEpoch(0),
+        ),
+        null,
+        null,
+        null,
+        null,
+        null,
+        null,
+        null,
+      ) {
+    isHttpProfilingAvailableResult = true;
+    _httpLoggingEnabled[_currentIsolateId] = false;
+    _socketProfilingEnabled[_currentIsolateId] = false;
+  }
+
+  static final _testVmFlagManager = VmFlagManager();
+
+  String _currentIsolateId = 'isolates/1';
+
+  /// A monotonic microsecond counter simulating the VM timeline clock.
+  int _timelineMicros = 1_000_000;
+
+  /// A map of isolate ID to the list of mock HTTP requests recorded on that
+  /// isolate.
+  final _httpProfiles = <String, List<HttpProfileRequest>>{};
+
+  /// A map of isolate ID to the list of mock socket statistics recorded on that
+  /// isolate.
+  final _socketProfiles = <String, List<SocketStatistic>>{};
+
+  /// A map tracking whether HTTP timeline logging is enabled (true/false) per
+  /// isolate ID.
+  final _httpLoggingEnabled = <String, bool>{};
+
+  /// A map tracking whether socket profiling is enabled (true/false) per isolate
+  /// ID.
+  final _socketProfilingEnabled = <String, bool>{};
+
+  /// The isolate ID currently returned by [forEachIsolate].
+  String get currentIsolateId => _currentIsolateId;
+
+  /// Sets the HTTP profile data that will be returned for [isolateId] when HTTP
+  /// timeline logging is enabled for that isolate.
+  void setHttpProfile(String isolateId, List<HttpProfileRequest> requests) {
+    _httpProfiles[isolateId] = requests;
+  }
+
+  /// Sets the socket profile data that will be returned for [isolateId] when
+  /// socket profiling is enabled for that isolate.
+  void setSocketProfile(String isolateId, List<SocketStatistic> sockets) {
+    _socketProfiles[isolateId] = sockets;
+  }
+
+  /// Whether HTTP timeline logging is enabled for [isolateId].
+  bool isHttpLoggingEnabled(String isolateId) =>
+      _httpLoggingEnabled[isolateId] ?? false;
+
+  /// Whether socket profiling is enabled for [isolateId].
+  bool isSocketProfilingEnabled(String isolateId) =>
+      _socketProfilingEnabled[isolateId] ?? false;
+
+  /// Simulates a hot restart by replacing the current isolate with a new one
+  /// that has HTTP logging and socket profiling disabled.
+  ///
+  /// Returns the ID of the new isolate.
+  String simulateHotRestart({String? newIsolateId}) {
+    final nextId = newIsolateId ?? '${_currentIsolateId}_restarted';
+    _currentIsolateId = nextId;
+    _httpLoggingEnabled[nextId] = false;
+    _socketProfilingEnabled[nextId] = false;
+    // Advance past pre-restart request timestamps so refresh logic treats them
+    // as stale on the new isolate.
+    _timelineMicros += 5_000_000;
+    return nextId;
+  }
+
+  /// Appends [request] to the HTTP profile for [isolateId].
+  void appendHttpRequest(String isolateId, HttpProfileRequest request) {
+    _httpProfiles[isolateId] = [...?_httpProfiles[isolateId], request];
+  }
+
+  @override
+  Future<Success> clearHttpProfileWrapper(String isolateId) async {
+    _httpProfiles[isolateId] = [];
+    return Success();
+  }
+
+  @override
+  Future<Success> clearSocketProfileWrapper(String isolateId) async {
+    _socketProfiles[isolateId] = [];
+    return Success();
+  }
+
+  @override
+  Future<void> forEachIsolate(Future<void> Function(IsolateRef) callback) =>
+      callback(IsolateRef.parse({'id': _currentIsolateId, 'name': 'main'})!);
+
+  @override
+  Future<HttpTimelineLoggingState> httpEnableTimelineLoggingWrapper(
+    String isolateId, [
+    bool? enabled,
+  ]) async {
+    if (enabled != null) {
+      _httpLoggingEnabled[isolateId] = enabled;
+      return HttpTimelineLoggingState(enabled: enabled);
+    }
+    return HttpTimelineLoggingState(
+      enabled: _httpLoggingEnabled[isolateId] ?? false,
+    );
+  }
+
+  @override
+  Future<SocketProfilingState> socketProfilingEnabledWrapper(
+    String isolateId, [
+    bool? enabled,
+  ]) async {
+    if (enabled != null) {
+      _socketProfilingEnabled[isolateId] = enabled;
+      return SocketProfilingState(enabled: enabled);
+    }
+    return SocketProfilingState(
+      enabled: _socketProfilingEnabled[isolateId] ?? false,
+    );
+  }
+
+  @override
+  Future<HttpProfile> getHttpProfileWrapper(
+    String isolateId, {
+    DateTime? updatedSince,
+  }) async {
+    if (!(_httpLoggingEnabled[isolateId] ?? false)) {
+      return HttpProfile(
+        requests: [],
+        timestamp: DateTime.fromMicrosecondsSinceEpoch(_timelineMicros),
+      );
+    }
+
+    var requests = List<HttpProfileRequest>.from(
+      _httpProfiles[isolateId] ?? const [],
+    );
+    if (updatedSince != null) {
+      final sinceMicros = updatedSince.microsecondsSinceEpoch;
+      requests = requests
+          .where(
+            (request) =>
+                request.startTime.microsecondsSinceEpoch >= sinceMicros,
+          )
+          .toList();
+    }
+    return HttpProfile(
+      requests: requests,
+      timestamp: DateTime.fromMicrosecondsSinceEpoch(_timelineMicros),
+    );
+  }
+
+  @override
+  Future<SocketProfile> getSocketProfileWrapper(String isolateId) async {
+    if (!(_socketProfilingEnabled[isolateId] ?? false)) {
+      return SocketProfile(sockets: []);
+    }
+    return SocketProfile(sockets: _socketProfiles[isolateId] ?? const []);
+  }
+
+  @override
+  Future<Timestamp> getVMTimelineMicros() async =>
+      Timestamp(timestamp: _timelineMicros);
+}
diff --git a/packages/devtools_app/test/screens/network/utils/network_lifecycle_test_utils.dart b/packages/devtools_app/test/screens/network/utils/network_lifecycle_test_utils.dart
new file mode 100644
index 0000000..7332fcb
--- /dev/null
+++ b/packages/devtools_app/test/screens/network/utils/network_lifecycle_test_utils.dart
@@ -0,0 +1,51 @@
+// Copyright 2026 The Flutter Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file or at https://developers.google.com/open-source/licenses/bsd.
+
+import 'package:devtools_app/devtools_app.dart';
+import 'package:devtools_app_shared/utils.dart';
+import 'package:devtools_test/devtools_test.dart';
+import 'package:flutter/foundation.dart';
+import 'package:flutter_test/flutter_test.dart';
+import 'package:vm_service/vm_service.dart';
+
+import 'hot_restart_network_vm_service.dart';
+
+Future<NetworkController> initNetworkLifecycleController({
+  required HotRestartNetworkVmService vmService,
+  required FakeServiceConnectionManager fakeServiceConnection,
+  List<HttpProfileRequest>? initialProfile,
+}) async {
+  if (initialProfile != null) {
+    vmService.setHttpProfile(vmService.currentIsolateId, initialProfile);
+  }
+  final controller = setUpNetworkLifecycleController(fakeServiceConnection);
+  await pumpEventQueue();
+  return controller;
+}
+
+NetworkController setUpNetworkLifecycleController(
+  FakeServiceConnectionManager fakeServiceConnection,
+) {
+  setGlobal(OfflineDataController, OfflineDataController());
+  setGlobal(ScreenControllers, ScreenControllers());
+  setGlobal(ServiceConnectionManager, fakeServiceConnection);
+  setGlobal(PreferencesController, PreferencesController());
+  screenControllers.register<NetworkController>(() => NetworkController());
+  return screenControllers.lookup<NetworkController>();
+}
+
+void notifyMainIsolateChanged(
+  FakeServiceConnectionManager connection,
+  String newIsolateId,
+) {
+  final isolateManager =
+      connection.serviceManager.isolateManager as FakeIsolateManager;
+  final isolateRef = IsolateRef.parse({'id': newIsolateId, 'name': 'main'})!;
+  (isolateManager.mainIsolate as ValueNotifier<IsolateRef?>).value = isolateRef;
+  isolateManager.notifyIsolateCreated(isolateRef);
+}
+
+void disposeNetworkLifecycleControllers() {
+  screenControllers.disposeConnectedControllers();
+}
diff --git a/packages/devtools_app/test/screens/network/utils/network_test_utils.dart b/packages/devtools_app/test/screens/network/utils/network_test_utils.dart
index 0d9506c..391f91c 100644
--- a/packages/devtools_app/test/screens/network/utils/network_test_utils.dart
+++ b/packages/devtools_app/test/screens/network/utils/network_test_utils.dart
@@ -6,6 +6,32 @@
 
 import '../../../test_infra/test_data/network.dart';
 
+/// Creates a minimal [HttpProfileRequest] for use in Network View tests.
+HttpProfileRequest createTestHttpRequest({
+  required String id,
+  required String method,
+  int startTime = 2_000_000,
+  String uri = 'https://example.com/test',
+}) {
+  final endTime = startTime + 1000;
+  return HttpProfileRequest.parse({
+    'type': 'HttpProfileRequest',
+    'id': id,
+    'isolateId': 'isolates/test',
+    'method': method,
+    'uri': uri,
+    'events': [],
+    'startTime': startTime,
+    'endTime': endTime,
+    'response': {
+      'startTime': startTime,
+      'endTime': endTime,
+      'redirects': [],
+      'statusCode': 200,
+    },
+  })!;
+}
+
 SocketProfile loadSocketProfile() {
   return SocketProfile(
     sockets: [
diff --git a/packages/devtools_app_shared/lib/src/service/isolate_manager.dart b/packages/devtools_app_shared/lib/src/service/isolate_manager.dart
index 9da67d8..71ac7d4 100644
--- a/packages/devtools_app_shared/lib/src/service/isolate_manager.dart
+++ b/packages/devtools_app_shared/lib/src/service/isolate_manager.dart
@@ -40,6 +40,13 @@
   final _isolateCreatedController = StreamController<IsolateRef?>.broadcast();
   final _isolateExitedController = StreamController<IsolateRef?>.broadcast();
 
+  /// Stream of isolates that have been created since the VM service connection
+  /// was opened.
+  ///
+  /// This can be used to detect when a new isolate is spawned, such as after a
+  /// hot restart.
+  Stream<IsolateRef?> get onIsolateCreated => _isolateCreatedController.stream;
+
   ValueListenable<IsolateRef?> get selectedIsolate => _selectedIsolate;
   final _selectedIsolate = ValueNotifier<IsolateRef?>(null);
 
diff --git a/packages/devtools_test/lib/src/mocks/fake_isolate_manager.dart b/packages/devtools_test/lib/src/mocks/fake_isolate_manager.dart
index dfc387e..5e9823f 100644
--- a/packages/devtools_test/lib/src/mocks/fake_isolate_manager.dart
+++ b/packages/devtools_test/lib/src/mocks/fake_isolate_manager.dart
@@ -4,6 +4,8 @@
 
 // ignore_for_file: invalid_use_of_visible_for_testing_member, devtools_test is only used in test code.
 
+import 'dart:async';
+
 import 'package:devtools_app_shared/service.dart';
 // ignore: implementation_imports, intentional import from src/
 import 'package:devtools_app_shared/src/service/isolate_manager.dart';
@@ -30,6 +32,20 @@
     IsolateRef.parse({'id': 'fake_main_isolate_id'}),
   );
 
+  final _isolateCreatedController = StreamController<IsolateRef?>.broadcast();
+
+  @override
+  Stream<IsolateRef?> get onIsolateCreated => _isolateCreatedController.stream;
+
+  /// Notifies listeners that a new isolate was created.
+  ///
+  /// This can be used in tests to simulate a hot restart spawning a new
+  /// isolate.
+  @visibleForTesting
+  void notifyIsolateCreated(IsolateRef isolate) {
+    _isolateCreatedController.add(isolate);
+  }
+
   @override
   ValueNotifier<List<IsolateRef>> get isolates {
     return _isolates ??= ValueNotifier([?_selectedIsolate.value]);