Você provavelmente já precisou desenvolver uma aplicação que trocasse dados com outra aplicação em tempo real ou de forma muito rápida.

Imagine um cenário onde você tem um aplicativo para clientes e um aplicativo para vendedores.

Quando um cliente realizar um pedido, o novo pedido deve ser disparado para todos os vendedores em tempo real. Quando um vendedor selecionar o pedido para atende-lo, o pedido em questão deve ser removido da lista de novos pedidos.

Existem muitas formas para resolver este problema. Neste post vou utilizar para o exemplo um aplicativo Xamarin Forms e para resolver o problema dos pedidos irei integrar meu aplicativo ao Realtime Database do Firebase.

Programação Reativa

O conceito de programação reativa, entre outros pontos, diz que aplicações reativas devem:

  • Reagir a eventos – a natureza de ser orientada a eventos permite as demais qualidades;
  • Reagir a cargas – foco na escalabilidade ao invés de performance voltada a um usuário apenas;
  • Reagir a falhas – ser resiliente com a capacidade de recuperação em todos os níveis;
  • Reagir aos usuários – combinar as características acima para proporcionar uma experiência de usuário interativa.

Você pode ler um pouco mais e se inteirar do assunto no site do manifesto da programação reativa em https://www.reactivemanifesto.org/

Xamarin Forms

De acordo com o site da própria tecnologia:
“O Xamarin.Forms é um conjunto de ferramentas UI multi-plataforma que permite aos desenvolvedores criar facilmente layouts de interface de usuário nativos que podem ser compartilhados em Android, iOS e Windows Phone.” Ele utiliza o XAML da Microsoft (já conhecido por quem já trabalhou com WPF e Windows Store Apps) para elaboração do layout que será compartilhado entre as plataformas móveis (iOS, Android e Windows).

Firebase Realtime Databse

O Firebase é um portal desenvolvido e administrado pela Google. Ele possui diversos serviços desenvolvidos para integrar a sua aplicação. Dados estas caracteristicas, ele encaixa-se no conceito de um BaaS (backend as a Service). Um dos serviços provisionado pelo Firebase é o Realtime Database. Um banco de dados NoSQL hospedado na nuvem. Com ele, você armazena e sincroniza dados entre os seus usuários em tempo real. Ele utilizar o formato JSON para armazenar os dados e você pode interagir com ele diretamente do portal do Firebase.

Criando a base de dados no Firebase

Acesse o site do Firebase pelo seu browser através do endereço https://firebase.google.com

Faça login com sua conta do google, e clique na opção Go To Console:

Clique na opção Adicionar Projeto, nomeie e selecione o país que irá hospedar a sua base de dados:

Acesse o menu Database:

Clique no botão Primeiros Passos.

Após isto você será direcionado para sua Realtime Databse.

Para efeitos de demonstração deste post, vamos desativar a opção de autenticação da base de dados. Mas atenção! Isto significa que qualquer pessoa que detenha o endereço da sua realtime database poderá inserir, atualizar e excluir itens, portanto, NUNCA UTILIZE ASSIM EM PRODUÇÃO

Altere as propriedades read and write para true no JSON e clique em publicar.

Para não me estender muito neste artigo vou abordar apenas o aplicativo do vendedor, então vamos precisar adicionar alguns pedidos manualmente (o que poderia ser feito por um aplicativo cliente sem problemas):

Clique no botão + ao lado do nome da base de dados para adicionar uma nova coleção:

Preencha o nome da coleção com pedidos:

Clique no + no final linha para adicionar as propriedades

Informe a chave (como se fosse um primary key) do pedido e depois clique novamente no + que aparecerá ao final da linha adicionada:

Para cada linha que você digitar o campo a esquerda deverá ser preenchida com nome da propriedade e a direita com o valor, assim como nos arquivos JSON. Para adicionar mais propriedades, clique no + ao lado da chave do pedido, neste exemplo no + ao lado do número 1. Preencha com as propriedades que serão utilizadas posteriormente no app e clique no botão Adicionar:

O campo IdVendedor será utilizado no app para informar qual o vendedor irá atender este pedido. Para adicionar mais itens, repita o procedimento.

Criando o aplicativo Xamarin Forms

Para este exemplo, vou usar o Visual Studio Community 2017, update 15.4. O framework do Xamarin está na versão 4.7.10.33

Vamos utilizar o projeto Cross Plataform App para criar nosso projeto Xamarin Forms:

File > New Project > Cross-Plataform > Cross Plataform App (Xamarin)

Vamos utilizar MVVM nesta demo para realizar a comunicação do front com back, caso você não conheça e queira aprender mais sobre o assunto recomendo este vídeo https://www.youtube.com/watch?v=ZXcDM0EwalA&t=1099s da galera do Monkey Nights!

Vamos adicionar a classe base da nossa ViewModel:

public class BaseViewModel : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    protected void OnPropertyChanged([CallerMemberName]string propertyName = "")
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

Vamos precisar também de uma classe modelo que será a representação do nosso pedido, ela deve conter todas as propriedades do pedido que foi criado na nossa coleção de pedidos, acrescida de uma propriedade que irá armazenar a chave do pedido:

public class Pedido
{

    public string KeyPedido { get; set; }

    public string Cliente { get; set; }

    public decimal Valor{ get; set; }

    public string Produto { get; set; }

    public int IdVendedor { get; set; }
}

A propriedade KeyPedido será preenchida com a Key do Pedido gerada pelo Firebase, você ver mais detalhes adiante.

Vamos criar também a ViewModel da nossa MainPage já com a lista de Pedidos e um Pedido que irá armazenar o pedido selecionado pelo usuário e também com um Command que será responsável por informar o Firebase que o vendedor irá atender o pedido:

public class MainPageViewModel : BaseViewModel
{
    private ObservableCollection<Pedido> _pedidos;

    public ObservableCollection<Pedido> Pedidos
    {
        get { return _pedidos; }

        set { _pedidos = value; OnPropertyChanged();}
    }

    public Pedido PedidoSelecionado;
    public ICommand AceitarPedidoCmd { get; set; }
}

É importante que a lista de pedidos seja do tipo ObservableCollection para que a tela seja notificada quando um novo item for incluído na lista, ou quando algum item for excluído.

Na nossa MainPage iremos ter uma ListView para receber os pedidos com um evento de ItemSelected e um Button para informar ao Firebase que o vendedor irá atender o pedido:

<ListView ItemsSource="{Binding Pedidos}"
ItemSelected="ListView_OnItemSelected">
    <ListView.ItemTemplate>
        <DataTemplate>
            <ViewCell>
                <Grid>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="*"></ColumnDefinition>
                        <ColumnDefinition Width="*"></ColumnDefinition>
                    </Grid.ColumnDefinitions>

                    <Grid.RowDefinitions>
                        <RowDefinition Height="Auto"></RowDefinition>
                        <RowDefinition Height="Auto"></RowDefinition>
                    </Grid.RowDefinitions>

                    <Label Text="{Binding Produto}"
                            Grid.Row="0"
                            Grid.Column="0"
                            FontSize="15"/>
                    <Label Text="{Binding Valor}"
                            Grid.Row="0"
                            Grid.Column="1"
                            FontAttributes="Bold"
                            FontSize="15"/>
                    <Label Text="{Binding Cliente}"
                            Grid.Row="1"
                            Grid.Column="0"
                            Grid.ColumnSpan="2"
                            FontSize="12"/>
                </Grid>
            </ViewCell>
        </DataTemplate>
    </ListView.ItemTemplate>
</ListView>

<Button Command="{Binding AceitarPedidoCmd}" Text="Atender!"/>

Não esqueça de setar o BindingContext no code-behind da sua página:

BindingContext = new MainPageViewModel();

Neste momento vamos criar o nosso método Listerner de Pedidos e o método Aceitar Pedido. A partir de agora vamos começar a integrar nosso aplicativo com o Firebase.

Para isto vamos utilizar a biblioteca FirebaseDatabase.net da Step-up-labs: https://github.com/step-up-labs/firebase-database-dotnet

Vamos utilizar esta biblioteca pois ela é cross plataform, então não vamos precisar nos preocupar com as diferenças entre iOS e Android e suporta o .Net Standart 1.1.

A biblioteca deve ser instalada em todos os projetos da Solution. Você pode instalar pelo Package Manager Console executando o comando:

Install-Package FirebaseDatabase.net

Na MainPageViewModel.cs vamos adicionar o cliente do Firebase e o endereço da base de dados do firebase:

Acesse sua conta do Firebase novamente, entre na sua base de dados criada anteriormente e copie o endereço:

Vamos criar uma constante na nossa MainPageViewModel.cs para armazenar este valor:

private readonly string ENDERECO_FIREBASE = "https://demoapp-33406.firebaseio.com/";

Vamos criar também a propriedade do client do firebase e instancia-lo no método construtor da nossa viewmodel juntamente com a nossa lista de pedidos e o nosso command de Aceitar Pedidos:

private readonly FirebaseClient _firebaseClient;

public MainPageViewModel()
{
    _firebaseClient = new FirebaseClient(ENDERECO_FIREBASE);
    Pedidos = new ObservableCollection<Pedido>();
    AceitarPedidoCmd = new Command(() => AceitarPedido());
}

Criando o Listener de Pedidos:

Na MainPageViewModel.cs vamos criar o método Listener de Pedidos do Firebase. Ele irá realizar uma subscrição para a API Rest base de dados que entre outros, suporta a API de transmissão que você pode usar para notificações em tempo real.

Vamos utilizar o subscribe do tipo Pedido que foi definido anteriormente para o filho pedidos, que foi a base de dados que criamos anteriormente:

private void ListenerPedidos()
{
    _firebaseClient
    .Child("pedidos")
    .AsObservable<Pedido>()
    .Subscribe(d =>
    {
        if (d.EventType == FirebaseEventType.InsertOrUpdate)
        {
            if (d.Object.IdVendedor == 0)
                AdicionarPedido(d.Key, d.Object);
            else
                RemoverPedido(d.Key);
        }
        else if (d.EventType == FirebaseEventType.Delete)
        {
            RemoverPedido(d.Key);
        }
    });
}

Perceba que ao definirmos a função para o método subscribe podemos realizar a verificação se o tipo de Evento recebido é um InsertOrUpdate ou se é do tipo Delete.

Também iremos verificar se o IdVendedor é igual a 0 para adicionar à lista de pedidos ou para remover.

Você pode utilizar a regra de negócio que melhor se adequa a sua necessidade. Neste exemplo, novos pedidos devem ter o IdVendedor igual a 0 e quando algum vendedor selecionar o pedido para atendimento vamos informar o ID do vendedor neste campo para que ele não apareça mais na lista de novos pedidos.

Vamos adicionar também os métodos responsáveis por adicionar e remover um pedido da lista de pedidos:

private void AdicionarPedido(string key, Pedido pedido)
{
    Pedidos.Add(new Pedido()
    {
        KeyPedido = key,

        Cliente = pedido.Cliente,

        Produto = pedido.Produto,

        Valor = pedido.Valor
    });
}

private void RemoverPedido(string pedidoKey)
{
    var pedido = Pedidos.FirstOrDefault(x => x.KeyPedido == pedidoKey);
    Pedidos.Remove(pedido);
}

O listener já está preparado para receber as atualizações em tempo real da base de dados do Firebase. Para que ele seja ativado quando nosso aplicativo for executado, iremos chamar o método ListenerPedidos no método criador da MainPageViewModel.cs, que ficará da seguinte maneira:

public MainPageViewModel()
{
    _firebaseClient = new FirebaseClient(ENDERECO_FIREBASE);
    Pedidos = new ObservableCollection<Pedido>();
    AceitarPedidoCmd = new Command(() => AceitarPedido());
    ListenerPedidos();
}

Por fim, vamos adicionar o método AceitarPedido, que será chamado pelo nosso command AceitarPedidoCmd:

private void AceitarPedido()
{
    PedidoSelecionado.IdVendedor = 1;

    _firebaseClient
        .Child("pedidos")
        .Child(PedidoSelecionado.KeyPedido)
        .PutAsync(PedidoSelecionado);
}

Nete método estamos informando para o Firebase que estamos enviando um registro do tipo pedido, com uma determinada chave única para nossa coleção de pedidos. Ao recebe-lo o Firebase irá identificar que o pedido já existe e, porque estamos fazendo um Put, irá atualizar o pedido através da chave informada.

Estamos também informando o valor 1 na propriedade IdVendedor para que quando o Firebase enviar o evento para nosso listener o pedido seja removido da lista de novos pedidos.

No code behind da nossa página vamos adicionar o evento seleção de um item da lista:

private void ListView_OnItemSelected(object sender, SelectedItemChangedEventArgs e)
{
    _viewModel.PedidoSelecionado = e.SelectedItem as Pedido;
}

Este evento já está relacionado na propriedade ItemSelected da ListView da MainPage.

Selecione a sua plataforma de preferência como projeto de inicialização e execute o aplicativo.

Para realizar o teste e checar se o aplicativo está reagindo em tempo real as alterações realizadas no Firebase, você pode selecionar um item da lista de clicar no botão Atender, o item deverá sumir da lista, pois foi o ID do vendedor foi atualizado para o valor 1 no Firebase.

Você também pode incluir novos itens na coleção do Firebase e verificar se aparece em tempo real na lista de novos pedidos do aplicativo.

Legal, não é? O Firebase é uma ferramenta muito poderosa e que pode nos ajudar a resolver diversos problemas. Apesar da sequência de passos parecer grande, para a finalidade do problema que estamos resolvendo, acredito que foi uma sequência aceitável.

Você gostou? Funcionou? Caso tenha alguma dúvida entre em contato, terei prazer em ajudar!

Você pode baixar o código fonte completo deste exemplo no GitHub:

https://github.com/AmorimRob/XamarinForms-RealtimeDatabase

#Ubuntu

Referencias:

https://www.infoq.com/br/news/2013/11/programacao-reativa

https://www.reactivemanifesto.org/

https://developer.xamarin.com/guides/xamarin-forms/

https://firebase.google.com/products/database/?hl=pt-br

Modificado pela ultima vez: 15 de maio de 2020

Comentários

Top

Elton Ventura 

Muito bom o post mano! Parabéns.

Robson, Muito bom o Post. Só tem uma pequena divergência entre o texto e o código. Na criação do JSON vc usa o termo “Valor”, mas no código a classe está como “Preco”. Uma sugestão seria vc disponibilizar o JSON de exemplo para importação. Ficaria mais simples.

    Autor
    Robson Soares Amorim 

    Agnaldo, muito obrigado pela observação! Você está correto, vou anotar isto e atualizar o post. Valeu! Ah, não disponibilizei o json pq a minha intenção era mostrar o passo a passo para criar a base de dados no firebase, talvez eu poderia ter feito os dois, obrigado pela sugestão!

Opa sou novo no blog e gostei muito funcionou perfeitamente, tbm sou novo com xamarin e se um dia você estiver com tempo de fazer a mesma coisa so que usando o azure ficarei muito agradecido

    Autor
    Robson Soares Amorim 

    Jadson, obrigado pelo comentário, anotei a sugestão! Valeu!

Robson, segui passo a passo como você fez, mas não mostra nada na ListView

    Autor
    Robson Soares Amorim 

    Olá Wagner! Obrigado pela leitura do post ! A primeira conexão entre o app e o firebase costuma demorar um pouco, cerca de 10 – 20 segundos dependendo do plano escolhido, tente fazer uma atualização em algum registro no firebase para verificar se ao atualizar um registro a conexão acontece com sucesso. Talvez esteja havendo algum delay nesta comunicação. No mais, eu checaria se o BindingContext está certinho e se a lista está com o método OnPropertyChanged(); sendo chamado após o set. Espero ter ajudado!

bom dia, segue todos os passos do artigo. o APP funcionou, porém tem uma demora ao carregar os dados quando entra no aplicativo. fica uns 10 segundos com a lista vazia e do nada aparecem os registros. o que poderia ser isso?

    Autor
    Robson Soares Amorim 

    Alessandro, Bom dia! Obrigado pela leitura e pelo comentário! Este tempo de espera deve-se a primeira conexão entre o App e o banco de dados do Firebase. É um delay esperado desta conexão com listener. Para contornar isto você pode realizar uma query no banco de dados assim que entrar na tela e iniciar o listener posteriormente apenas para inserções/atualizações de registros.

outra coisa que acontece é que a lista de registros vai duplicando de tempo em tempo. como se a rotina nao limpasse e insere tudo de novo.

    Autor
    Robson Soares Amorim 

    Neste caso, você precisará realizar uma checagem se o dado ja está contido na lista antes de adicionar os registros no próprio método de AdicionarPedido ou no tratamento do FirebaseEventType. Optei por não abordar o tratamento no post pelo tamanho do texto que está um pouco extenso.

Boa tarde, Robson. Eu estou a procura de um exemplo muito parecido com esse, mas que funcione offline, quando o dispositivo estiver sem Internet. Poderia me dar uma dica de quais ajustes precisariam serem feitos nesse seu exemplo para suportar o Offline? Obrigado.

    Autor
    Robson Soares Amorim 

    Olá Leandro! Boa tarde! Obrigado pela leitura e pelo comentário! Infelizmente com Xamarin Forms a biblioteca de integração ainda não suporta trabalhos offline. As bibliotecas oficiais da Google suportam trabalhos offline na plataforma Android e iOS https://firebase.google.com/docs/database/android/offline-capabilities?hl=pt-br https://firebase.google.com/docs/database/ios/offline-capabilities?hl=pt-br Te mandei por email uma ideia de como você poderia realizar esta abordagem offline com Xamarin Forms. Abraço!

      Jonathan Cristian Rodrigues 

      Boa noite Robson, parabéns pelos post! muito didatico!!! também gostaria de receber este email… obrigado

        Autor
        Robson Soares Amorim 

        Olá Jonathan! Boa tarde! Obrigado pela leitura e pelo comentário! Fico feliz que você tenha curtido o post! No caso do email, se for pra receber os posts, basta você informar seu email no campo no lado direito superior da home page do blog e todo novo post você receberá por email Obrigado!

Robson, muito legal o passo a passo. Já me deu uma boa direção de como acessar o firebase com Xamarin Cross Platform. Mas eu estou conseguindo fazer inclusão de dados mas quando vou ler apresenta o seguinte erro: Firebase.Database.FirebaseException: Exception occured while processing the request. Url: https://meubanco.firebaseio.com/pedidos/.json Request Data: Response: [null,{“Cliente”:”TesteCliente”,”IdVendedor”:0,”KeyPedido”:1,”Prouto”:”TesteProduto”,”Valor”:100},{“Cliente”:”Teste02″,”IdVendedor”:0,”KeyPedido”:2,”Produto”:”Teste02Prod”,”Valor”:100},{“Cliente”:”Cliente03″,”IdVendedor”:0,”KeyPedido”:3,”Produto”:”TesteProduto03″,”Valor”:300}] Aparentemente o Firebase retorna os dados, mas dá erro na API. o comando que estou dando é o seguinte var items = await _firebaseClient.Child(“pedidos”) .OnceAsync(); Você tem ideia do que pode ser?

    Autor
    Robson Soares Amorim 

    Olá! Bom dia! Obrigado pela leitura e pelo comentário! Pelo JSON, acho que não está vindo a key do pedido retornada pelo firebase. Pode ser na estrutura da base, veja se o niveis estão dividios de forma q o pedido tenha um key propria do firebase abs

Rodrigo Bora 

Muito bom cara muito util e pratico. Eu nao estou conseguindo fazer a insercao de imagens do firebase storege voce tem algo para me ajudar . Por favor é meu tcc e só acho coisa que nao da

Escreva uma resposta ou comentário

Seu endereço de e-mail não será publicado.

Esse site utiliza o Akismet para reduzir spam. Aprenda como seus dados de comentários são processados.