.claude/skills/flutter-isolates/SKILL.md
Guia especializado em Isolates no Flutter. Use este skill sempre que o usuário perguntar sobre paralelismo, concorrência, performance de UI, jank, tarefas pesadas em Flutter, ou mencionar qualquer uma das APIs — compute(), Isolate.spawn, Isolate.run, SendPort, ReceivePort. Também deve ser ativado quando o usuário perguntar se deve usar Isolate para determinada tarefa — o skill inclui critérios claros de decisão. Ative mesmo que o usuário não mencione Isolate explicitamente, mas descreva um problema de performance ou travamento de UI em Flutter. Activate even when the user says 'the UI is freezing while processing data', 'the app lags during heavy computation', 'parsing large JSON is blocking the thread', 'how to run this without blocking the UI', or 'the scroll is janky during data processing' without explicitly mentioning Isolate or compute().
npx skillsauth add andrelucassvt/CleanMacForDevsWeb flutter-isolatesInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Isolate não é padrão — é otimização pontual.
async/awaitresolve ~90% dos casos. Isolate só se justifica quando há trabalho CPU-intensivo que está causando (ou pode causar) jank na UI.
Sempre responda essa pergunta antes de sugerir Isolate:
A tarefa bloqueia a thread por mais de ~4ms?
|
NÃO → async/await é suficiente
|
SIM → É trabalho de I/O (rede, disco)?
|
SIM → async/await é suficiente (já é não-bloqueante)
|
NÃO → É cálculo CPU-intensivo?
|
SIM → Use Isolate ✅
| Situação | Exemplo concreto | |---|---| | JSON grande (> ~1MB) | Parsear resposta de API volumosa | | Criptografia / hashing | bcrypt, SHA em loop | | Compressão | gzip de arquivos grandes | | Processamento de imagem | Filtros manuais, resize sem lib nativa | | Algoritmos pesados | Pathfinding, simulações, ML local | | Parsing de arquivos | CSV/XML grande linha a linha |
| Situação | Por quê não |
|---|---|
| Chamadas HTTP | http.get() já é async, não bloqueia |
| Queries ao banco (sqflite, Drift) | I/O assíncrono por natureza |
| Leitura de arquivo pequeno | File.readAsString() é async |
| Cálculos simples | Overhead do Isolate > tempo da tarefa |
| Atualizar estado / chamar setState | Impossível — Isolate não acessa UI |
compute() — Mais simples, uso mais comum// Ideal para: tarefa única, sem comunicação contínua
// Restrição: a função DEVE ser top-level ou static
import 'package:flutter/foundation.dart';
// ✅ Top-level — obrigatório
List<Produto> _parsearProdutos(String jsonStr) {
final lista = jsonDecode(jsonStr) as List;
return lista.map((e) => Produto.fromJson(e)).toList();
}
// Na UI:
final produtos = await compute(_parsearProdutos, responseBody);
Quando preferir: tarefa pontual, sem necessidade de progresso ou múltiplas mensagens.
Isolate.run() — Flutter 3+ / Dart 2.19+// Mais moderno que compute(), sintaxe mais limpa
import 'dart:isolate';
final resultado = await Isolate.run(() {
// código pesado aqui
return _processarDados(dados);
});
Quando preferir: mesmos casos que compute(), mas com sintaxe mais ergonômica.
Isolate.spawn + SendPort/ReceivePort — Controle total// Ideal para: comunicação contínua, progresso, múltiplas mensagens
import 'dart:isolate';
Future<void> processarComProgresso(List<int> dados) async {
final receivePort = ReceivePort();
await Isolate.spawn(_worker, receivePort.sendPort);
// Recebe SendPort do worker para comunicação bidirecional
final workerPort = await receivePort.first as SendPort;
final respostaPort = ReceivePort();
workerPort.send({'dados': dados, 'reply': respostaPort.sendPort});
await for (final msg in respostaPort) {
if (msg is double) {
print('Progresso: ${(msg * 100).toStringAsFixed(0)}%');
} else if (msg is List<int>) {
print('Concluído: $msg');
break;
}
}
}
// Roda no Isolate separado
void _worker(SendPort mainPort) async {
final port = ReceivePort();
mainPort.send(port.sendPort);
await for (final msg in port) {
final dados = msg['dados'] as List<int>;
final reply = msg['reply'] as SendPort;
final resultado = <int>[];
for (int i = 0; i < dados.length; i++) {
resultado.add(dados[i] * 2);
if (i % 100 == 0) {
reply.send(i / dados.length); // progresso
}
}
reply.send(resultado); // resultado final
}
}
Quando preferir: precisa de progresso em tempo real, múltiplas tarefas no mesmo Isolate, ou ciclo de vida longo.
setState, BuildContext, Provider, Riverpod, etc.TransferableTypedData.SharedPreferences, Hive, etc. precisam ser reinicializadas dentro do Isolate.flutter run --profile// 🚨 Isso PROVAVELMENTE vai causar jank:
void _aoClicar() {
final resultado = jsonDecode(respostaGigante); // síncrono, pesado
setState(() => _itens = resultado);
}
// ✅ Correto:
void _aoClicar() async {
final resultado = await compute(jsonDecode, respostaGigante);
setState(() => _itens = resultado);
}
Para apps reais, encapsule o Isolate em um serviço:
class ProcessamentoService {
// Reutiliza o mesmo Isolate para múltiplas tarefas
Isolate? _isolate;
SendPort? _sendPort;
Future<void> inicializar() async {
final receivePort = ReceivePort();
_isolate = await Isolate.spawn(_entryPoint, receivePort.sendPort);
_sendPort = await receivePort.first;
}
Future<T> executar<T>(Map<String, dynamic> tarefa) async {
final replyPort = ReceivePort();
_sendPort!.send({...tarefa, 'reply': replyPort.sendPort});
return await replyPort.first as T;
}
void dispose() {
_isolate?.kill(priority: Isolate.immediate);
}
static void _entryPoint(SendPort mainPort) async {
final port = ReceivePort();
mainPort.send(port.sendPort);
await for (final msg in port) {
// processar tarefas
}
}
}
| Necessidade | API recomendada |
|---|---|
| Tarefa simples e pontual | compute() |
| Tarefa simples, Dart 2.19+ | Isolate.run() |
| Progresso em tempo real | Isolate.spawn + ReceivePort |
| Isolate de longa vida / reutilizável | Isolate.spawn com loop |
| Worker pool (múltiplos paralelos) | Pacote worker_manager ou flutter_isolate |
worker_manager — pool de Isolates reutilizáveisflutter_isolate — Isolate com suporte a plugins nativosisolate_handler — abstração de alto nívelcompute()Última atualização: 28 de março de 2026
testing
Create new skills, modify and improve existing skills, and measure skill performance. Use when users want to create a skill from scratch, edit, or optimize an existing skill, run evals to test a skill, benchmark skill performance with variance analysis, or optimize a skill's description for better triggering accuracy. Activate even when the user says 'create a skill for X', 'the skill is not triggering', 'improve this skill description', 'the agent is not using the skill', 'add a skill to teach the agent how to do X', 'this skill is wrong', or 'update the skill' without explicitly mentioning evals or benchmark.
development
Implements Flutter reusable widgets following the project architecture. Use whenever creating or modifying widgets in presentation/<feature>/widgets/, presentation/<feature>/content/, or common/widgets/. Covers StatelessWidget vs StatefulWidget decision, Entity as parameter, i18n, dispose, componentization rules, and when to access the Cubit via context.read. Activate even when the user says 'extract this to a widget', 'create a list item widget', 'build a reusable card', 'factor out this UI block', 'create a component for this', or 'this View is getting too big' without explicitly mentioning StatelessWidget or reusable components.
tools
Implements Flutter View screens following the project architecture. Use whenever creating or modifying a View (StatefulWidget + Cubit + BlocBuilder), adding a new screen, wiring up BlocBuilder/BlocConsumer/BlocListener, setting up SafeArea, or navigating from the View. Covers State, Cubit, View file, route, DI registration, and common mistakes. Activate even when the user just says "create a screen" or "add a new page", without explicitly mentioning Cubit or BLoC.
testing
Implements Flutter Cubit and State (View Model layer) following the project architecture. Use whenever creating or modifying a Cubit or State class, adding an async method to a Cubit, handling form submission or validation, implementing debounce search, managing loading/error/navigation states, or wiring a Cubit to a Repository or StorageService. Covers sealed States, async patterns with Result<T>, CRUD Cubits, local persistence via StorageService, navigation states, debounce, and common mistakes. Activate even when the user says "add a method", "handle the loading state", or "save locally" without explicitly mentioning Cubit or BLoC.