En esta lección, aprenderemos cómo obtener datos de Internet en una aplicación Flutter. Este es un aspecto crucial para muchas aplicaciones modernas que dependen de datos en tiempo real o de servicios web para funcionar correctamente.

Objetivos de la Lección

  • Entender cómo realizar solicitudes HTTP en Flutter.
  • Aprender a manejar respuestas HTTP.
  • Implementar la obtención de datos desde una API REST.

Requisitos Previos

  • Conocimientos básicos de Dart y Flutter.
  • Familiaridad con los conceptos de programación asíncrona.

Contenido

Introducción a las Solicitudes HTTP

HTTP (HyperText Transfer Protocol) es el protocolo utilizado para la comunicación entre clientes y servidores en la web. En Flutter, podemos realizar solicitudes HTTP para obtener datos de servidores remotos utilizando el paquete http.

Configuración del Paquete HTTP

Para realizar solicitudes HTTP en Flutter, primero necesitamos agregar el paquete http a nuestro proyecto.

  1. Abre el archivo pubspec.yaml de tu proyecto.
  2. Agrega la dependencia http en la sección dependencies:
dependencies:
  flutter:
    sdk: flutter
  http: ^0.13.3
  1. Guarda el archivo y ejecuta flutter pub get para instalar la dependencia.

Realizando una Solicitud GET

Una solicitud GET se utiliza para obtener datos de un servidor. A continuación, se muestra cómo realizar una solicitud GET en Flutter:

import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('Obteniendo Datos de Internet'),
        ),
        body: Center(
          child: FutureBuilder(
            future: fetchData(),
            builder: (context, snapshot) {
              if (snapshot.connectionState == ConnectionState.waiting) {
                return CircularProgressIndicator();
              } else if (snapshot.hasError) {
                return Text('Error: ${snapshot.error}');
              } else {
                return Text('Datos: ${snapshot.data}');
              }
            },
          ),
        ),
      ),
    );
  }

  Future<String> fetchData() async {
    final response = await http.get(Uri.parse('https://jsonplaceholder.typicode.com/posts/1'));

    if (response.statusCode == 200) {
      return response.body;
    } else {
      throw Exception('Error al obtener datos');
    }
  }
}

Explicación del Código

  1. Importaciones: Importamos los paquetes flutter/material.dart y http.
  2. Main Function: La función main ejecuta la aplicación.
  3. MyApp Class: Definimos una clase MyApp que extiende StatelessWidget.
  4. FutureBuilder: Utilizamos FutureBuilder para manejar la solicitud asíncrona y mostrar los datos obtenidos.
  5. fetchData Function: Definimos una función fetchData que realiza una solicitud GET a una URL y devuelve los datos obtenidos.

Manejo de Respuestas HTTP

Es importante manejar adecuadamente las respuestas HTTP para asegurarnos de que nuestra aplicación funcione correctamente incluso cuando ocurren errores.

Ejemplo de Manejo de Errores

Future<String> fetchData() async {
  try {
    final response = await http.get(Uri.parse('https://jsonplaceholder.typicode.com/posts/1'));

    if (response.statusCode == 200) {
      return response.body;
    } else {
      throw Exception('Error al obtener datos: ${response.statusCode}');
    }
  } catch (e) {
    throw Exception('Error de red: $e');
  }
}

En este ejemplo, utilizamos un bloque try-catch para manejar posibles errores de red.

Ejemplo Práctico

Vamos a crear una aplicación que obtenga una lista de publicaciones desde una API y las muestre en una lista.

import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('Lista de Publicaciones'),
        ),
        body: PostsList(),
      ),
    );
  }
}

class PostsList extends StatefulWidget {
  @override
  _PostsListState createState() => _PostsListState();
}

class _PostsListState extends State<PostsList> {
  Future<List<Post>> fetchPosts() async {
    final response = await http.get(Uri.parse('https://jsonplaceholder.typicode.com/posts'));

    if (response.statusCode == 200) {
      List jsonResponse = json.decode(response.body);
      return jsonResponse.map((post) => Post.fromJson(post)).toList();
    } else {
      throw Exception('Error al obtener publicaciones');
    }
  }

  @override
  Widget build(BuildContext context) {
    return FutureBuilder<List<Post>>(
      future: fetchPosts(),
      builder: (context, snapshot) {
        if (snapshot.connectionState == ConnectionState.waiting) {
          return CircularProgressIndicator();
        } else if (snapshot.hasError) {
          return Text('Error: ${snapshot.error}');
        } else {
          return ListView.builder(
            itemCount: snapshot.data!.length,
            itemBuilder: (context, index) {
              return ListTile(
                title: Text(snapshot.data![index].title),
                subtitle: Text(snapshot.data![index].body),
              );
            },
          );
        }
      },
    );
  }
}

class Post {
  final int id;
  final String title;
  final String body;

  Post({required this.id, required this.title, required this.body});

  factory Post.fromJson(Map<String, dynamic> json) {
    return Post(
      id: json['id'],
      title: json['title'],
      body: json['body'],
    );
  }
}

Explicación del Código

  1. fetchPosts Function: Realiza una solicitud GET para obtener una lista de publicaciones y las convierte en una lista de objetos Post.
  2. Post Class: Define una clase Post con un método fromJson para convertir JSON en un objeto Post.
  3. FutureBuilder: Utiliza FutureBuilder para manejar la solicitud asíncrona y mostrar la lista de publicaciones.

Ejercicio Práctico

Ejercicio

Crea una aplicación Flutter que obtenga una lista de usuarios desde la API https://jsonplaceholder.typicode.com/users y los muestre en una lista. Cada elemento de la lista debe mostrar el nombre y el correo electrónico del usuario.

Solución

import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('Lista de Usuarios'),
        ),
        body: UsersList(),
      ),
    );
  }
}

class UsersList extends StatefulWidget {
  @override
  _UsersListState createState() => _UsersListState();
}

class _UsersListState extends State<UsersList> {
  Future<List<User>> fetchUsers() async {
    final response = await http.get(Uri.parse('https://jsonplaceholder.typicode.com/users'));

    if (response.statusCode == 200) {
      List jsonResponse = json.decode(response.body);
      return jsonResponse.map((user) => User.fromJson(user)).toList();
    } else {
      throw Exception('Error al obtener usuarios');
    }
  }

  @override
  Widget build(BuildContext context) {
    return FutureBuilder<List<User>>(
      future: fetchUsers(),
      builder: (context, snapshot) {
        if (snapshot.connectionState == ConnectionState.waiting) {
          return CircularProgressIndicator();
        } else if (snapshot.hasError) {
          return Text('Error: ${snapshot.error}');
        } else {
          return ListView.builder(
            itemCount: snapshot.data!.length,
            itemBuilder: (context, index) {
              return ListTile(
                title: Text(snapshot.data![index].name),
                subtitle: Text(snapshot.data![index].email),
              );
            },
          );
        }
      },
    );
  }
}

class User {
  final int id;
  final String name;
  final String email;

  User({required this.id, required this.name, required this.email});

  factory User.fromJson(Map<String, dynamic> json) {
    return User(
      id: json['id'],
      name: json['name'],
      email: json['email'],
    );
  }
}

Explicación del Código

  1. fetchUsers Function: Realiza una solicitud GET para obtener una lista de usuarios y las convierte en una lista de objetos User.
  2. User Class: Define una clase User con un método fromJson para convertir JSON en un objeto User.
  3. FutureBuilder: Utiliza FutureBuilder para manejar la solicitud asíncrona y mostrar la lista de usuarios.

Conclusión

En esta lección, hemos aprendido cómo obtener datos de Internet en una aplicación Flutter utilizando el paquete http. Hemos cubierto cómo realizar solicitudes GET, manejar respuestas HTTP y mostrar los datos obtenidos en la interfaz de usuario. Además, hemos implementado un ejemplo práctico y un ejercicio para reforzar los conceptos aprendidos.

En la próxima lección, aprenderemos cómo parsear datos JSON obtenidos de una API.

Curso de Desarrollo con Flutter

Módulo 1: Introducción a Flutter

Módulo 2: Conceptos Básicos de Programación en Dart

Módulo 3: Widgets en Flutter

Módulo 4: Gestión de Estado

Módulo 5: Navegación y Enrutamiento

Módulo 6: Redes y APIs

Módulo 7: Persistencia y Almacenamiento

Módulo 8: Conceptos Avanzados de Flutter

Módulo 9: Pruebas y Depuración

Módulo 10: Despliegue y Mantenimiento

Módulo 11: Flutter para Web y Escritorio

© Copyright 2024. Todos los derechos reservados