Hoje vamos continuar a apresentar como exibir uma lista de dados usando Flutter, desta vez obtendo os dados no formato JSON via Http. |
Continuando a terceira parte do artigo, hoje veremos como obter dados de uma API REST no formato JSON via HTTP e exibir em um ListView criado usando o construtor ListView.builder.
Obtendos dados da internet no formato JSON
Obter dados da internet é uma tarefa comum hoje em dia, e o Flutter e o Dart permitem realizar essa tarefa de forma bem simples.
O roteiro básico a seguir é :
- Adicionar o pacote http
- Fazer uma requisição de rede usando o pacote http
- Converter a resposta em um objeto Dart personalizado
- Buscar e exibir os dados com o Flutter
É isso que iremos fazer neste artigo.
Vamos exibir no ListView os dados obtidos no formato JSON a partir de uma API REST. Existem muitas serviços REST disponíveis que oferecem serviços para obter dados.
Neste artigo vamos usar os dados disponível neste endpoint: https://unsplash.com/napi/photos/Q14J2k8VE3U/related
Abaixo temos os dados no formato JSON retornados por esta url:
{
"total":20,
"results":[
{
"id":"hzgs56Ze49s",
"created_at":"2015-04-25T07:52:00-04:00",
"updated_at":"2019-04-21T19:55:18-04:00",
"width":5616,
"height":3744,
"color":"#876B59",
"description":"party fans raised their hands",
"alt_description":"person performing heart hand gesture",
"urls":{
"raw":"https://images.unsplash.com/photo-1429962714451-bb934ecdc4ec?ixlib=rb-1.2.1",
"full":"https://images.unsplash.com/photo-1429962714451-bb934ecdc4ec?ixlib=rb-1.2.1&q=85&fm=jpg&crop=entropy&cs=srgb",
"regular":"https://images.unsplash.com/photo-1429962714451-bb934ecdc4ec?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=1080&fit=max",
"small":"https://images.unsplash.com/photo-1429962714451-bb934ecdc4ec?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=400&fit=max",
"thumb":"https://images.unsplash.com/photo-1429962714451-bb934ecdc4ec?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=200&fit=max"
},
"links":{
"self":"https://api.unsplash.com/photos/hzgs56Ze49s",
"html":"https://unsplash.com/photos/hzgs56Ze49s",
"download":"https://unsplash.com/photos/hzgs56Ze49s/download",
"download_location":"https://api.unsplash.com/photos/hzgs56Ze49s/download"
},
"categories":[
],
"sponsored":false,
"sponsored_by":null,
"sponsored_impressions_id":null,
"likes":1174,
"liked_by_user":false,
"current_user_collections":[
],
"user":{
"id":"wdFc4ZqCkWo",
"updated_at":"2019-04-13T17:28:40-04:00",
"username":"anthonydelanoix",
"name":"Anthony DELANOIX",
"first_name":"Anthony",
"last_name":"DELANOIX",
"twitter_username":"anthonydelanoix",
"portfolio_url":"http://www.instagram.com/antho.dlx",
"bio":"\u2661 If you like what you see here, follow my adventures and more on Instagram @antho_dlx \u2661\r\n25 years old, born in south of France, living in Paris. Scandinavian culture lover, working in digital marketing, and trying to travel as much as possible.",
"location":"Paris",
"links":{
"self":"https://api.unsplash.com/users/anthonydelanoix",
"html":"https://unsplash.com/@anthonydelanoix",
"photos":"https://api.unsplash.com/users/anthonydelanoix/photos",
"likes":"https://api.unsplash.com/users/anthonydelanoix/likes",
"portfolio":"https://api.unsplash.com/users/anthonydelanoix/portfolio",
"following":"https://api.unsplash.com/users/anthonydelanoix/following",
"followers":"https://api.unsplash.com/users/anthonydelanoix/followers"
},
"profile_image":{
"small":"https://images.unsplash.com/profile-1456878349584-ba7fc98ac955?ixlib=rb-1.2.1&q=80&fm=jpg&crop=faces&cs=tinysrgb&fit=crop&h=32&w=32",
"medium":"https://images.unsplash.com/profile-1456878349584-ba7fc98ac955?ixlib=rb-1.2.1&q=80&fm=jpg&crop=faces&cs=tinysrgb&fit=crop&h=64&w=64",
"large":"https://images.unsplash.com/profile-1456878349584-ba7fc98ac955?ixlib=rb-1.2.1&q=80&fm=jpg&crop=faces&cs=tinysrgb&fit=crop&h=128&w=128"
},
"instagram_username":"antho.dlx",
"total_collections":0,
"total_likes":11,
"total_photos":169,
"accepted_tos":true
}
}
]
}
Vamos obter os dados das urls das imagens, descrição e likes, de forma que nosso ListView vai exibir em uma coluna a imagem, e, em uma linha vai exibir a descrição e a quantidade de likes.
Nota: Se você quiser obter os objetos Dart a partir do formato JSON pode utilizar este link:https://javiercbk.github.io/json_to_dart/
Criando o projeto Flutter
Eu estou usando o Flutter versão 1.2.1, e como editor de código estou usando o VS Code com o plugin Flutter instalado.
No Visual Studio Code tecle CTRL+ SHIFT+P para abrir a paleta de comandos e a seguir selecione a opção : Fluter:New Project
A seguir informe o nome do projeto : flutter_http_json e tecle ENTER.
Na janela de diálogo a seguir, selecione a pasta onde o projeto vai ser salvo e clique em :
Select a folder to create the project in
O Flutter vai criar um projeto padrão onde todo o código da aplicação vai estar no arquivo main.dart dentro da pasta lib do projeto.
Como podemos acessar dados via HTTP no Flutter ?
Conforme a documentação temos que usar o pacote http 0.12.0+2 que contém um conjunto de funções de alto nível que torna fácil consumir recursos HTTP. Sendo independente de plataforma e podendo ser usado na linha de comando e no browser.
Para isso vamos incluir no arquivo pubspec.yaml a referência ao pacote http: ^0.12.0.0+2 conforme abaixo:
Além disso vamos ter que importar o pacote : import ‘package:http/http.dart’; no arquivo main.dart.
O código usado para obter dados via Http é dado a seguir:
Future<String> getJSONData() async {
var response = await http.get(
Uri.encodeFull("https://unsplash.com/napi/photos/Q14J2k8VE3U/related"),
headers: {"Accept": "application/json"}
);
setState(() {
// otem os dados JSON
data = json.decode(response.body)['results'];
});
return "Dados obtidos com sucesso";
}
|
No código acima você pode estranhar o uso de Future.
O que é Future ?
Um Future é um objeto Future<T>, que representa uma operação assíncrona que produz um resultado do tipo T. Se o resultado não for um valor utilizável, o tipo do futuro será Future<void>. Quando uma função que retorna um futuro é invocada, duas coisas acontecem:
1- A função enfileira o trabalho a ser feito e retorna um objeto Future não concluído.
2- Posteriormente, quando a operação for concluída, o objeto Future será concluído com um valor ou com um erro.
E quando escrevemos código que depende de um Future podemos usar async e await.
A seguir definimos a url e o cabeçalho application/json e obtemos os dados atualizando o estado.
Exibindo Imagens no ListView
Como vamos exibir imagens, para obter desempenho, vamos usar imagens em cache.
Segundo a documentação temos que usar o pacote cached_network_image 0.7.0 que usa construtores para o placeholder e o widget de erro e usa o sqflite para o gerenciamento de cache.
Para isso vamos incluir no arquivo pubspec.yaml a referência ao pacote cached_network_image 0.7.0 conforme abaixo:
Teremos também que importar o pacote : import ‘package:cached_network_image/cached_network_image.dart’; no arquivo main.dart.
Definindo o código do projeto
Abra o arquivo main.dart na pasta lib e defina os seguintes imports:
import ‘package:flutter/material.dart’;
import ‘package:http/http.dart’ as http;
import ‘dart:convert’;
import ‘package:cached_network_image/cached_network_image.dart’;
O primeiro implementa o material design, o segundo permite realizar requisições http, o terceiro permite codificar e decodificar o JSON e o último permite trabalhar com imagens no cache.
A seguir defina o ponto de entrada da aplicação no método main() e o código do widget MyApp que estende deStatelessWidget:
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'ListView - Http e Json'),
);
}
}
Agora precisamos incluir o código da classe MyHomePage() onde definimos a classe privada _MyHomePageState que sobrescreve o método createState():
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() => _MyHomePageState();
}
|
Na classe _MyHomePageState() obtemos os dados no formato JSON e invocamos o widget _criaListView():
class _MyHomePageState extends State<MyHomePage> {
List data;
// Função para obter os dados JSON
Future<String> getJSONData() async {
var response = await http.get(
// codifiga a url
Uri.encodeFull("https://unsplash.com/napi/photos/Q14J2k8VE3U/related"),
// Aceita somente resposta JSON
headers: {"Accept": "application/json"}
);
setState(() {
// Pega os dados JSON
data = json.decode(response.body)['results'];
});
return "Dados obtidos com sucesso";
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: _criaListView(),
);
}
|
O widget _criaListaView cria um listview usando o construtor ListView.builder e invoca o widget _criaImagemColuna()passando os dados para exibição:
Widget _criaListView() {
return ListView.builder(
padding: const EdgeInsets.all(16.0),
itemCount: data == null ? 0 : data.length,
itemBuilder: (context, index) {
return _criaImagemColuna(data[index]);
}
);
}
|
O widget _criaImagemColuna define um contâiner e um boxdecoration e tem como filho uma coluna onde vai exibir a imagem usando cache, depois invoca o widget _criaLinha passando os dados para exibir:
Widget _criaImagemColuna(dynamic item) => Container(
decoration: BoxDecoration(
color: Colors.white54
),
margin: const EdgeInsets.all(4),
child: Column(
children: [
new CachedNetworkImage(
imageUrl: item['urls']['small'],
placeholder: (context, url) => new CircularProgressIndicator(),
errorWidget: (context, url, error) => new Icon(Icons.error),
fadeOutDuration: new Duration(seconds: 1),
fadeInDuration: new Duration(seconds: 3),
),
_criaLinha(item)
],
),
);
|
O widget _criaLinha define um ListTile no ListView e exibe a descrição e a quantidade de likes:
Widget _criaLinha(dynamic item) {
return ListTile(
title: Text(
item['description'] == null ? '': item['description'],
),
subtitle: Text("Likes: " + item['likes'].toString()),
);
}
@override
void initState() {
super.initState();
// Chama o método getJSONData() quando a app inicializa
this.getJSONData();
}
}
|
Para executar podemos pressionar F5 ou no terminal de comandos, estando posicionado na pasta do projeto, basta digitar : flutter run -d all
Executando o projeto iremos obter o resultado abaixo:
Vemos assim os dados obtidos via http no formato JSON sendo exibidos no ListView.
Pegue o projeto do arquivo main.dart aqui: main_dart.zip
“Palavra fiel é esta: que, se morrermos com ele, também com ele viveremos;
Se sofrermos, também com ele reinaremos; se o negarmos, também ele nos negará;
Se formos infiéis, ele permanece fiel; não pode negar-se a si mesmo.”
2 Timóteo 2:11-13
Referências:
- Seção VB .NET do Site Macoratti.net
- Super DVD .NET – A sua porta de entrada na plataforma .NET
- Super DVD Vídeo Aulas – Vídeo Aula sobre VB .NET, ASP .NET e C#
- Super DVD C# – Recursos de aprendizagens e vídeo aulas para C#
- Seção C# do site Macoratti.net
- Seção ASP .NET do site Macoratti .net
- Curso Básico VB .NET – Vídeo Aulas
- Curso C# Básico – Vídeo Aulas
-
Curso Fundamentos da Programação Orientada a Objetos com VB .NET
- macoratti – YouTube
- Jose C Macoratti (@macorati) | Twitter
- Seção Mobilie – Xamarin Android
- Flutter – Apresentando o widget MaterialApp – Macoratti
- Flutter – Apresentando Flutter Studio – Macoratti
- Flutter – Lista Básica – Macoratti
- Flutter – Apresentando Widgets – Macoratti
- Flutter – Obtendo dados da Web – Macoratti