devtools icon indicating copy to clipboard operation
devtools copied to clipboard

On hot restart, the main thread and isolated threads will cause devtools to show a paused state

Open maxfrees opened this issue 6 months ago • 9 comments

https://github.com/user-attachments/assets/87e149ac-3274-41b8-9a25-7cc3e7bd46bd

Each time, it needs to be clicked twice to restore before it can run normally. Is there any way to solve this problem

[!] Flutter (Channel stable, 3.32.0, on Microsoft Windows [ 10.0.19045.5854], locale zh-CN) [923ms]
• Flutter version 3.32.0 on channel stable at E:\flutter\default
! Warning: flutter on your path resolves to E:\flutter\versions\stable\bin\flutter, which is not inside your
current Flutter SDK checkout at E:\flutter\default. Consider adding E:\flutter\default\bin to the front of your
path.
! Warning: dart on your path resolves to E:\flutter\versions\stable\bin\dart, which is not inside your current
Flutter SDK checkout at E:\flutter\default. Consider adding E:\flutter\default\bin to the front of your path.
• Upstream repository https://github.com/flutter/flutter.git
• Framework revision be698c48a6 (2 days ago), 2025-05-19 12:59:14 -0700
• Engine revision 1881800949
• Dart version 3.8.0
• DevTools version 2.45.1
• Pub download mirror https://pub.flutter-io.cn/
• Flutter download mirror https://storage.flutter-io.cn/
• If those were intentional, you can disregard the above warnings; however it is recommended to use "git" directly
to perform update checks and upgrades.

maxfrees avatar Jun 06 '25 08:06 maxfrees

This looks like a duplicate of https://github.com/flutter/devtools/issues/9185. @maxfrees is there something fundamentally different between these two issues? If not, it would be best to keep the communication on a single issue so that context is not lost.

kenzieschmoll avatar Jun 06 '25 21:06 kenzieschmoll

closed another issue with flutter version information

maxfrees avatar Jun 07 '25 02:06 maxfrees

Hope to resolve this as soon as possible.

maxfrees avatar Jun 07 '25 02:06 maxfrees

When is it expected to be resolved?

maxfrees avatar Jun 07 '25 13:06 maxfrees

Hi @maxfrees. Per Flutter issue hygiene guidelines, please refrain from adding comments that are just asking for updates. "Asking for updates is also not generally helpful, because it just leads to issues being full of comments asking for updates and that makes finding useful information in a bug harder." This issue will be updated when we have an update to share. Thanks!

kenzieschmoll avatar Jun 10 '25 17:06 kenzieschmoll

Can you provide clear reproduction steps? That would help our team to resolve the problem. Thanks.

kenzieschmoll avatar Jun 10 '25 17:06 kenzieschmoll

@kenzieschmoll

import 'dart:isolate';

import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Isolate Demo',
      theme: ThemeData(colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple)),
      home: const MyHomePage(title: 'Flutter Isolate Demo'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key, required this.title});

  final String title;

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class IsolateMessage {
  final int value;
  final SendPort responsePort;

  IsolateMessage(this.value, this.responsePort);
}

class _MyHomePageState extends State<MyHomePage> {
  final int _counter = 0;
  String _isolateResult = "No result yet";
  bool _isCalculating = false;
  int _inputValue = 1000000;

  ReceivePort? _receivePort;
  Isolate? _isolate;
  SendPort? _isolateSendPort;

  void _startHeavyTask() async {
    if (_isCalculating) return;

    setState(() {
      _isCalculating = true;
      _isolateResult = "..";
    });

    _receivePort = ReceivePort();

    _isolate = await Isolate.spawn(_isolateEntryPoint, _receivePort!.sendPort);

    _receivePort!.listen((message) {
      if (message is SendPort) {
        _isolateSendPort = message;
        _sendMessageToIsolate();
      } else {
        setState(() {
          _isolateResult = "message: $message";
          _isCalculating = false;
        });
        _cleanupIsolate();
      }
    });
  }

 
  void _sendMessageToIsolate() {
    if (_isolateSendPort != null) {
      final responsePort = ReceivePort();

      _isolateSendPort!.send(IsolateMessage(_inputValue, responsePort.sendPort));

      responsePort.listen((message) {
        setState(() {
          _isolateResult = "s: $message";
        });
        responsePort.close();
      });
    }
  }

  void _cleanupIsolate() {
    _isolate?.kill(priority: Isolate.immediate);
    _isolate = null;
    _receivePort?.close();
    _receivePort = null;
    _isolateSendPort = null;
  }

  static void _isolateEntryPoint(SendPort mainSendPort) {
    final receivePort = ReceivePort();

    mainSendPort.send(receivePort.sendPort);

    receivePort.listen((message) {
      if (message is IsolateMessage) {
        int limit = message.value;

        message.responsePort.send("limit: $limit");

        int sum = 0;
        for (int i = 0; i < limit; i++) {
          sum += i;
        }

        mainSendPort.send(sum);
      }
    });
  }

  @override
  void dispose() {
    _cleanupIsolate();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(backgroundColor: Theme.of(context).colorScheme.inversePrimary, title: Text(widget.title)),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            const Text('demo:'),
            Text('$_counter', style: Theme.of(context).textTheme.headlineMedium),
            const SizedBox(height: 30),
            Padding(
              padding: const EdgeInsets.symmetric(horizontal: 50),
              child: TextField(
                keyboardType: TextInputType.number,
                onChanged: (value) {
                  if (value.isNotEmpty) {
                    _inputValue = int.tryParse(value) ?? 1000000;
                  }
                },
              ),
            ),
            const SizedBox(height: 20),
            ElevatedButton(
              onPressed: _isCalculating ? null : _startHeavyTask,
              child: Text(_isCalculating ? 'send...' : 'send'),
            ),
            const SizedBox(height: 20),
            Text(_isolateResult),
          ],
        ),
      ),
    );
  }
}

https://github.com/user-attachments/assets/6425fa51-31d9-4c97-846e-7b8be49e350a

maxfrees avatar Jun 11 '25 01:06 maxfrees

Thank you for the code snippet. It is not immediately clear from your video what the reproduction steps are. Can you provide textual instructions like:

  1. Run app on from VS code on Desktop.
  2. Trigger a hot restart. Expected behavior: ... Actual behavior: ....

Clear instructions like this make it easier to reproduce your use case.

Additionally, I don't actually see where DevTools is used in your video. Are you actually opening Flutter DevTools at any point during your workflow?

kenzieschmoll avatar Jun 11 '25 18:06 kenzieschmoll

If the code contains an isolation thread, Each time a hot restart is performed and the "Send Isolation Thread Message" is clicked, there is a probability that the thread will be in a paused state, blocking the code execution. It is necessary to manually click "Start" for it to execute.

maxfrees avatar Jun 12 '25 03:06 maxfrees

Hi @maxfrees - I'm unable to reproduce this with the sample app. I also don't think that this is a DevTools issue, since DevTools is not involved here.

If you are still facing this, could you open up an issue in the Dart SDK?

Thank you!

elliette avatar Jul 09 '25 23:07 elliette