Flutter - Fazendo o Parser de JSON


 Hoje veremos como realizar o parser de arquivos JSON a nível básico

O Flutter é um SDK de aplicativo móvel do Google que ajuda a criar aplicativos móveis modernos para iOS e Android usando uma única (quase) base de código.

Se você não conhece o Flutter veja o meu artigo :  Flutter - Primeiros contatos e impressões

Fazendo o Parser do JSON

JSON significa Java Script Object Notation e é um formato para intercâmbio de dados aberto e baseado em texto fácil de ler e de escrever.

As principais regras de sintaxe JSON são:

A linguagem Dart oferece suporte para analisar arquivos JSON, e, usando a biblioteca convert.dart para converter o Json (se for o json válido) em um Map com chaves de string e objetos dinâmicos.

Você pode analisar o json diretamente e usar o mapa ou pode analisá-lo e colocá-lo em um objeto tipado para que seus dados tenham uma estrutura e sejam mais fáceis de manter.

Nota : Na linguagem Dart , a classe Map é uma coleção de pares chave/valor, a partir dos quais você recupera um valor usando sua chave associada.

Podemos fazer o parse diretamente conforme mostra o código a seguir:

import 'dart:convert';
var jsonData = '{ "nome" : "Paulo", "email" : "paulo@hotmail.com"  }';

var parsedJson = json.decode(jsonData);

print('${parsedJson.runtimeType} : $parsedJson');

Executando o código acima em : dartpad.dartlang.org iremos obter o seguinte resultado:

Podemos então acessar os dados analisados  usando o índice da chave no mapa retornado. Vamos indexar no mapa e obter o nome e o email.

import 'dart:convert';
void main() {
  var jsonData = '{ "nome" : "Paulo", "email" : "paulo@hotmail.com"  }';
  var parsedJson = json.decode(jsonData);
  print('${parsedJson.runtimeType} : $parsedJson');  
  var nome = parsedJson['nome'];
  var email = parsedJson['email'];  
  print('$nome e $email');  
}

Executando o código acima em : dartpad.dartlang.org iremos obter o seguinte resultado:

Vamos iniciar com uma estrutura de um arquivo JSON bem simples que representa um Map ou mapa.

Veremos agora como fazer um mapeamento para um arquivo JSON simples

Mapeando JSON para objetos

A seguir temos o arquivo aluno.json (criado na pasta Json do projeto)

{
  "id":"1245",
  "nome":"Paula Soares",
  "nota" : 90
}

Assim nas strings JSON podemos ter duas possibilidades de Map:

  1. Se houver apenas chaves {} a string vai conter um Map<x,y> que é representando por pares chave:
  2. Se houver colchetes [] a string vai conter uma lista de mapas List<Map>;

Nosso arquuivo aluno.json é um mapa (Map) onde id é chave e 1245 é o valor para id.

Vamos criar um arquivo PODO (Plain Old Dart Object) para este arquivo JSON.(criado na pasta model)

class Aluno {
  String alunoId;
  String alunoNome;
  int alunoNotas;
  Aluno({
    this.alunoId,
    this.alunoNome,
    this.alunoNotas
  });
}

Mas olhando a nossa classe Aluno e para o arquivo aluno.json parece que não existe um mapeamento entre eles, mesmo os nomes das entidades não coincidem.

Então o nosso trabalho será realizar o mapeamento dos membros da classe para o objeto json.

Para isso precisamos criar um método factory.

Conforme a documentação da linguagem Dart usamos a palavra-chave factory para implementar um construtor que não cria uma nova instância da sua classe (como um Singleton) e é isso que precisamos.

factory Aluno.fromJson(Map<String, dynamic> parsedJson){
    return Aluno(
      alunoId: parsedJson['id'],
      alunoNome : parsedJson['nome'],
      alunoNotas : parsedJson ['nota']
    );
  }

Neste código estamos criando um método factory chamado Aluno.fromJson, cujo objetivo é simplesmente desserializar o nosso JSON, onde desserializar significa converter de bytes para objeto sendo que o processo oposto, converter de objeto para uma sequência linear de bytes é conhecido como serializar.

Agora, observe o parâmetro usado no método fromJson. É um Map<String, dynamic>, e, isso significa que ele mapeia uma chave String com um valor dynamic. É exatamente por isso que precisamos identificar a estrutura. Se essa estrutura json fosse uma lista de mapas, esse parâmetro teria sido definido diferente.

Nossa classe agora ficou assim:

class Aluno {
  String alunoId;
  String alunoNome;
  int alunoNotas;
  Aluno({
    this.alunoId,
    this.alunoNome,
    this.alunoNotas
  });
factory Aluno.fromJson(Map<String, dynamic> parsedJson){
    return Aluno(
      alunoId: parsedJson['id'],
      alunoNome : parsedJson['nome'],
      alunoNotas : parsedJson ['nota']
    );
  }
}

E como podemos acessar o objeto ?

Vamos definir um código Dart em um arquivo chamado aluno_service.dart em uma pasta services para retornar os valores do objeto Aluno.

import 'dart:convert';
import 'dart:async' show Future;
import 'package:flutter/services.dart' show rootBundle;
import '../model/aluno.dart';
Future<String> _carregaAlunoJson() async {
  return await rootBundle.loadString('Json/aluno.json');
}
Future carregaAluno() async {
  String jsonString = await _carregaAlunoJson();
  final jsonResponse = json.decode(jsonString);

  Aluno aluno = new Aluno.fromJson(jsonResponse);

  print(aluno.alunoNotas);
}

Aqui estamos usando um 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.

No método carregaAluno estamos realizando as seguintes tarefas :

  1. carregamos os dados JSON a partir do arquivo aluno.json
  2. decodificamos a string JSON
  3. desserializamos a resposta Json decodificada chamando o método Aluno.fromJson
  4. Imprimimos o valor da nota do aluno a partir da classe Aluno

Para ver isso funcionando na janela do console defina no arquivo main.dart o código abaixo:

import 'package:flutter/material.dart';
import '../services/aluno_service.dart';
void main() {
  runApp(new MyApp());
  carregaAluno();
}
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
        home: Text("Json")
    );
  }
}

Pegue os arquivos do projeto aqui : projeto_flutter_json.txt

"Disse-lhe, pois, Pilatos: Logo tu és rei? Jesus respondeu: Tu dizes que eu sou rei. Eu para isso nasci, e para isso vim ao mundo, a fim de dar testemunho da verdade. Todo aquele que é da verdade ouve a minha voz."
João 18:37

Veja os Destaques e novidades do SUPER DVD Visual Basic (sempre atualizado) : clique e confira !

Quer migrar para o VB .NET ?

Quer aprender C# ??

Quer aprender os conceitos da Programação Orientada a objetos ?

Quer aprender o gerar relatórios com o ReportViewer no VS 2013 ?

Referências:


José Carlos Macoratti