← Назад к вопросам
Какие знаешь виды snapshot?
2.0 Middle🔥 161 комментариев
#State Management#Тестирование
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI26 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Виды Snapshot в Flutter
Snapshot (снимок состояния) — это объект в Flutter, который содержит информацию о состоянии асинхронной операции. Используется с `FutureBuilder` и `StreamBuilder`.
Основные виды snapshots
1. ConnectionState
Определяет состояние асинхронного подключения:
enum ConnectionState {
none, // Нет асинхронной операции
waiting, // В процессе выполнения (loading)
active, // Активное соединение (для Stream)
done, // Завершено успешно
}
// Использование
FutureBuilder<String>(
future: fetchData(),
builder: (context, snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.none:
return const Text('No data');
case ConnectionState.waiting:
return const CircularProgressIndicator();
case ConnectionState.active:
return const Text('Active');
case ConnectionState.done:
if (snapshot.hasError) {
return Text('Error: ${snapshot.error}');
}
return Text('Data: ${snapshot.data}');
}
},
)
2. FutureBuilder Snapshot
Используется для работы с одноразовыми асинхронными операциями (Future).
class FutureBuilderExample extends StatelessWidget {
Future<String> fetchUserName() async {
await Future.delayed(const Duration(seconds: 2));
return 'John Doe';
}
@override
Widget build(BuildContext context) {
return FutureBuilder<String>(
future: fetchUserName(),
builder: (context, snapshot) {
// snapshot.connectionState — состояние соединения
// snapshot.data — результат (если есть)
// snapshot.error — ошибка (если есть)
// snapshot.hasData — true если есть данные
// snapshot.hasError — true если есть ошибка
if (snapshot.hasData) {
return Text('Hello, ${snapshot.data}!');
} else if (snapshot.hasError) {
return Text('Error: ${snapshot.error}');
} else {
return const CircularProgressIndicator();
}
},
);
}
}
3. StreamBuilder Snapshot
Используется для работы с потоками данных (Stream).
class StreamBuilderExample extends StatelessWidget {
Stream<int> countStream() async* {
for (int i = 0; i < 10; i++) {
await Future.delayed(const Duration(seconds: 1));
yield i;
}
}
@override
Widget build(BuildContext context) {
return StreamBuilder<int>(
stream: countStream(),
initialData: 0,
builder: (context, snapshot) {
// snapshot.connectionState — состояние потока
// snapshot.data — последнее значение из потока
// snapshot.error — ошибка потока
// snapshot.hasData — true если есть данные
// snapshot.hasError — true если есть ошибка
if (snapshot.hasError) {
return Text('Error: ${snapshot.error}');
}
if (snapshot.connectionState == ConnectionState.waiting) {
return const Text('Waiting...');
}
return Text('Count: ${snapshot.data}');
},
);
}
}
Методы и свойства snapshot
AsyncSnapshot<T> {
// Состояние соединения
ConnectionState connectionState;
// Данные результата
T? data;
// Ошибка (если есть)
Object? error;
// Stack trace ошибки
StackTrace? stackTrace;
// Проверочные методы
bool get hasData => data != null;
bool get hasError => error != null;
// Получение значения или выброс ошибки
T get requireData => ...
}
Виды снимков по типам данных
Snapshot с примитивными типами
// Snapshot<String>
FutureBuilder<String>(
future: Future.value('Hello'),
builder: (context, AsyncSnapshot<String> snapshot) {
return Text(snapshot.data ?? 'Loading');
},
)
// Snapshot<int>
StreamBuilder<int>(
stream: Stream.periodic(Duration(seconds: 1), (count) => count),
builder: (context, AsyncSnapshot<int> snapshot) {
return Text('${snapshot.data ?? 0}');
},
)
Snapshot со сложными типами
class User {
final String name;
final int age;
User({required this.name, required this.age});
}
// Snapshot<User>
FutureBuilder<User>(
future: fetchUser(),
builder: (context, AsyncSnapshot<User> snapshot) {
if (snapshot.hasData) {
final user = snapshot.data!;
return Text('${user.name}, ${user.age}');
}
return const SizedBox();
},
)
// Snapshot<List<User>>
StreamBuilder<List<User>>(
stream: watchUsers(),
builder: (context, AsyncSnapshot<List<User>> snapshot) {
if (snapshot.hasData) {
return ListView.builder(
itemCount: snapshot.data!.length,
itemBuilder: (context, index) {
final user = snapshot.data![index];
return ListTile(title: Text(user.name));
},
);
}
return const CircularProgressIndicator();
},
)
Снимки с обработкой ошибок
FutureBuilder<String>(
future: riskyOperation(),
builder: (context, snapshot) {
// Вариант 1: последовательная проверка
if (snapshot.connectionState == ConnectionState.waiting) {
return const Center(child: CircularProgressIndicator());
}
if (snapshot.hasError) {
return Center(
child: Text('Error: ${snapshot.error}'),
);
}
if (snapshot.hasData) {
return Text('Success: ${snapshot.data}');
}
return const SizedBox();
},
)
// Вариант 2: с обработкой ошибок
FutureBuilder<String>(
future: riskyOperation(),
builder: (context, snapshot) {
return snapshot.when(
data: (data) => Text(data),
loading: () => const CircularProgressIndicator(),
error: (error, stackTrace) => Text('Error: $error'),
);
},
)
Snapshot в Riverpod (альтернатива)
В современном Flutter часто используют Riverpod вместо FutureBuilder:
final userProvider = FutureProvider<User>((ref) async {
return fetchUser();
});
class UserWidget extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
final userAsync = ref.watch(userProvider);
// AsyncValue с тремя состояниями: data, loading, error
return userAsync.when(
data: (user) => Text(user.name),
loading: () => const CircularProgressIndicator(),
error: (error, stackTrace) => Text('Error: $error'),
);
}
}
Практический пример: загрузка списка
class PostsPage extends StatelessWidget {
Future<List<Post>> fetchPosts() async {
final response = await http.get(
Uri.parse('https://api.example.com/posts'),
);
if (response.statusCode == 200) {
final List<dynamic> json = jsonDecode(response.body);
return json.map((p) => Post.fromJson(p)).toList();
} else {
throw Exception('Failed to load posts');
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Posts')),
body: FutureBuilder<List<Post>>(
future: fetchPosts(),
builder: (context, snapshot) {
// Loading state
if (snapshot.connectionState == ConnectionState.waiting) {
return const Center(
child: CircularProgressIndicator(),
);
}
// Error state
if (snapshot.hasError) {
return Center(
child: Text(
'Error: ${snapshot.error}',
style: const TextStyle(color: Colors.red),
),
);
}
// Empty data
if (!snapshot.hasData || snapshot.data!.isEmpty) {
return const Center(
child: Text('No posts found'),
);
}
// Success state with data
return ListView.builder(
itemCount: snapshot.data!.length,
itemBuilder: (context, index) {
final post = snapshot.data![index];
return Card(
margin: const EdgeInsets.all(8),
child: ListTile(
title: Text(post.title),
subtitle: Text(post.body),
),
);
},
);
},
),
);
}
}
Ключевые точки
✅ ConnectionState.waiting — загрузка данных ✅ snapshot.hasData — данные успешно получены ✅ snapshot.hasError — произошла ошибка ✅ snapshot.data — само значение ✅ snapshot.error — объект ошибки
Когда использовать каждый тип
| Тип | Когда использовать |
|---|---|
| FutureBuilder | Одноразовые операции (загрузка данных при открытии страницы) |
| StreamBuilder | Постоянные обновления (реал-тайм данные, WebSocket) |
| Riverpod | Сложное управление состоянием в крупных приложениях |
Snapshot — это фундаментальная концепция в Flutter для работы с асинхронными операциями.