Obtener datos de internet
Cómo obtener datos a través de Internet utilizando el paquete http.
Obtener datos de internet es necesario para la mayoría de las aplicaciones.
Afortunadamente, Dart y Flutter proporcionan herramientas, como el
paquete http, para este tipo de trabajo.
Esta receta utiliza los siguientes pasos:
- Agrega el paquete
http. - Realiza una solicitud de red utilizando el paquete
http. - Convierte la respuesta en un objeto Dart personalizado.
- Obtén y muestra los datos con Flutter.
1. Agregar el paquete http
#
El paquete http proporciona la
forma más sencilla de obtener datos de internet.
Para agregar el paquete http como dependencia,
ejecuta flutter pub add:
flutter pub add http
Importa el paquete http.
import 'package:http/http.dart' as http;
Si estás haciendo el despliegue en Android, edita tu archivo AndroidManifest.xml para
agregar el permiso de Internet.
<!-- Required to fetch data from the internet. -->
<uses-permission android:name="android.permission.INTERNET" />
Del mismo modo, si estás haciendo el despliegue en macOS, edita tus
archivos macos/Runner/DebugProfile.entitlements y macos/Runner/Release.entitlements
para incluir el entitlement del cliente de red.
<!-- Required to fetch data from the internet. -->
<key>com.apple.security.network.client</key>
<true/>
2. Realizar una solicitud de red
#Esta receta cubre cómo obtener un álbum de ejemplo desde
JSONPlaceholder utilizando el método http.get().
Future<http.Response> fetchAlbum() {
return http.get(Uri.parse('https://jsonplaceholder.typicode.com/albums/1'));
}
El método http.get() devuelve un Future que contiene una Response.
Futurees una clase principal de Dart para trabajar con operaciones asíncronas. Un objeto Future representa un valor potencial o un error que estará disponible en algún momento en el futuro.- La clase
http.Responsecontiene los datos recibidos de una llamada http exitosa.
3. Convertir la respuesta en un objeto Dart personalizado
#Aunque es fácil realizar una solicitud de red, trabajar con un
Future<http.Response> crudo no es muy conveniente.
Para facilitarte la vida,
convierte la http.Response en un objeto de Dart.
Crear una clase Album
#
Primero, crea una clase Album que contenga los datos de la
solicitud de red. Incluye un constructor factory que
crea un Album a partir de JSON.
Convertir JSON utilizando pattern matching es solo una opción. Para obtener más información, consulta el artículo completo sobre JSON y serialización.
class Album {
final int userId;
final int id;
final String title;
const Album({required this.userId, required this.id, required this.title});
factory Album.fromJson(Map<String, dynamic> json) {
return switch (json) {
{'userId': int userId, 'id': int id, 'title': String title} => Album(
userId: userId,
id: id,
title: title,
),
_ => throw const FormatException('Failed to load album.'),
};
}
}
Convertir la http.Response en un Album
#
Ahora, utiliza los siguientes pasos para actualizar la función fetchAlbum()
para que devuelva un Future<Album>:
- Convierte el cuerpo de la respuesta en un JSON
Mapcon el paquetedart:convert. - Si el servidor devuelve una respuesta correcta con un código de estado de
200, entonces convierte el JSON
Mapen unAlbumutilizando el método factoryfromJson(). - Si el servidor no devuelve una respuesta correcta con un código de estado de 200,
entonces lanza una excepción.
(Incluso en el caso de una respuesta de servidor "404 Not Found",
lanza una excepción. No devuelvas
null. Esto es importante al examinar los datos ensnapshot, como se muestra a continuación).
Future<Album> fetchAlbum() async {
final response = await http.get(
Uri.parse('https://jsonplaceholder.typicode.com/albums/1'),
headers: {'Accept': 'application/json'},
);
if (response.statusCode == 200) {
// If the server did return a 200 OK response,
// then parse the JSON.
return Album.fromJson(jsonDecode(response.body) as Map<String, dynamic>);
} else {
// If the server did not return a 200 OK response,
// then throw an exception.
throw Exception('Failed to load album');
}
}
¡Genial! Ahora tienes una función que obtiene un álbum de internet.
4. Obtener los datos
#Llama al método fetchAlbum() ya sea en
initState()
o en los métodos didChangeDependencies().
El método initState() se llama exactamente una vez y nunca más.
Si deseas tener la opción de recargar la API en respuesta al cambio de un
InheritedWidget,
coloca la llamada en el método
didChangeDependencies().
Consulta State
para más detalles.
class _MyAppState extends State<MyApp> {
late Future<Album> futureAlbum;
@override
void initState() {
super.initState();
futureAlbum = fetchAlbum();
}
// ···
}
Este Future se utiliza en el siguiente paso.
5. Mostrar los datos
#Para mostrar los datos en pantalla, utiliza el
widget FutureBuilder.
El widget FutureBuilder viene con Flutter y
facilita el trabajo con fuentes de datos asíncronas.
Debes proporcionar dos parámetros:
- El
Futurecon el que quieres trabajar. En este caso, el future devuelto por la funciónfetchAlbum(). - Una función
builderque le indica a Flutter qué renderizar, según el estado delFuture: cargando, éxito o error.
Ten en cuenta que snapshot.hasData solo devuelve true
cuando el snapshot contiene un valor de datos no nulo.
Debido a que fetchAlbum solo puede devolver valores no nulos,
la función debe lanzar una excepción
incluso en el caso de una respuesta del servidor "404 Not Found".
Lanzar una excepción establece snapshot.hasError a true,
lo cual se puede utilizar para mostrar un mensaje de error.
De lo contrario, se mostrará el spinner.
FutureBuilder<Album>(
future: futureAlbum,
builder: (context, snapshot) {
if (snapshot.hasData) {
return Text(snapshot.data!.title);
} else if (snapshot.hasError) {
return Text('${snapshot.error}');
}
// By default, show a loading spinner.
return const CircularProgressIndicator();
},
)
¿Por qué se llama a fetchAlbum() en initState()?
#Aunque es conveniente,
no se recomienda realizar una llamada a la API en un método build().
Flutter llama al método build() cada vez que necesita
cambiar algo en la vista,
y esto sucede con sorprendente frecuencia.
Si colocas el método fetchAlbum() dentro de build(), se llamará
repetidamente en cada reconstrucción, lo que ralentizará la aplicación.
Almacenar el resultado de fetchAlbum() en una variable de estado asegura que
el Future se ejecute solo una vez y luego se almacene en caché para las
reconstrucciones posteriores.
Pruebas
#Para obtener información sobre cómo probar esta funcionalidad, consulta las siguientes recetas:
Ejemplo completo
#import 'dart:async';
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
Future<Album> fetchAlbum() async {
final response = await http.get(
Uri.parse('https://jsonplaceholder.typicode.com/albums/1'),
headers: {'Accept': 'application/json'},
);
if (response.statusCode == 200) {
// If the server did return a 200 OK response,
// then parse the JSON.
return Album.fromJson(jsonDecode(response.body) as Map<String, dynamic>);
} else {
// If the server did not return a 200 OK response,
// then throw an exception.
throw Exception('Failed to load album');
}
}
class Album {
final int userId;
final int id;
final String title;
const Album({required this.userId, required this.id, required this.title});
factory Album.fromJson(Map<String, dynamic> json) {
return switch (json) {
{'userId': int userId, 'id': int id, 'title': String title} => Album(
userId: userId,
id: id,
title: title,
),
_ => throw const FormatException('Failed to load album.'),
};
}
}
void main() => runApp(const MyApp());
class MyApp extends StatefulWidget {
const MyApp({super.key});
@override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
late Future<Album> futureAlbum;
@override
void initState() {
super.initState();
futureAlbum = fetchAlbum();
}
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Fetch Data Example',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
),
home: Scaffold(
appBar: AppBar(title: const Text('Fetch Data Example')),
body: Center(
child: FutureBuilder<Album>(
future: futureAlbum,
builder: (context, snapshot) {
if (snapshot.hasData) {
return Text(snapshot.data!.title);
} else if (snapshot.hasError) {
return Text('${snapshot.error}');
}
// By default, show a loading spinner.
return const CircularProgressIndicator();
},
),
),
),
);
}
}
A menos que se indique lo contrario, la documentación de este sitio refleja Flutter 3.44.0. Página actualizada por última vez el 2026-05-05. Ver código fuente oreportar un problema.