Partilhar via


Comunicação entre componentes flexíveis

Observação

Este eBook foi publicado na primavera de 2017 e não foi atualizado desde então. Há muito no livro que permanece valioso, mas parte do material está desatualizado.

O padrão de publicação-assinatura é um padrão de troca de mensagens em que os publicadores enviam mensagens sem ter conhecimento de nenhum receptor, conhecido como assinante. Da mesma forma, os assinantes escutam mensagens específicas, sem ter conhecimento de nenhum publicador.

Os eventos no .NET implementam o padrão de publicação-assinatura, e são a abordagem mais simples e direta para uma camada de comunicação entre os componentes se o acoplamento solto não é necessário, como um controle e a página que o contém. No entanto, os tempos de vida do publicador e do assinante são acoplados por referências de objeto entre si e o tipo de assinante deve ter uma referência para o tipo de publicador. Isso pode criar problemas de gerenciamento de memória, especialmente quando há objetos de curta duração que assinam o evento de um objeto estático ou de longa duração. Se o manipulador de eventos não for removido, o assinante será mantido ativo pela referência a ele no publicador e isso impedirá ou atrasará a coleta de lixo do assinante.

Introdução ao MessagingCenter

A Xamarin.FormsMessagingCenter classe implementa o padrão publish-subscribe, permitindo a comunicação baseada em mensagem entre componentes inconvenientes para vincular por referências de objeto e tipo. Esse mecanismo permite que publicadores e assinantes se comuniquem sem uma referência entre eles, ajudando a reduzir as dependências entre os componentes, permitindo também que os componentes sejam desenvolvidos e testados independentemente.

A classe MessagingCenter fornece a funcionalidade de publicação-assinatura multicast. Isso significa que pode haver vários publicadores que publicam uma única mensagem e pode haver vários assinantes ouvindo a mesma mensagem. A Figura 4-1 ilustra essa relação:

Funcionalidade de publicação/assinatura multicast

Figura 4-1: Funcionalidade de publicação/assinatura multicast

Os publicadores enviam mensagens usando o método MessagingCenter.Send, enquanto os assinantes ouvem mensagens usando o método MessagingCenter.Subscribe. Além disso, os assinantes também podem cancelar a assinatura de mensagens, se necessário, usando o método MessagingCenter.Unsubscribe.

Internamente, a classe MessagingCenter usa referências fracas. Isso significa que ela não manterá os objetos ativos e permitirá que eles sejam coletados como lixo. Portanto, só deverá ser necessário cancelar a assinatura de uma mensagem quando uma classe não desejar mais recebê-la.

O aplicativo móvel eShopOnContainers usa a MessagingCenter classe para se comunicar entre componentes flexívelmente acoplados. O aplicativo define três mensagens:

  • A mensagem AddProduct é publicada pela classe CatalogViewModel quando um item é adicionado à cesta de compras. Em troca, a BasketViewModel classe assina a mensagem e incrementa o número de itens na cesta de compras em resposta. Além disso, a classe também cancela a BasketViewModel assinatura dessa mensagem.
  • A Filter mensagem é publicada pela CatalogViewModel classe quando o usuário aplica uma marca ou filtro de tipo aos itens exibidos do catálogo. Em troca, a CatalogView classe assina a mensagem e atualiza a interface do usuário para que apenas os itens que correspondem aos critérios de filtro sejam exibidos.
  • A ChangeTab mensagem é publicada pela MainViewModel classe quando o CheckoutViewModel navega para o MainViewModel seguinte, a criação e o envio bem-sucedidos de um novo pedido. Em troca, a MainView classe assina a mensagem e atualiza a interface do usuário para que a guia Meu perfil esteja ativa, para mostrar os pedidos do usuário.

Observação

Embora a classe MessagingCenter permita a comunicação entre classes pouco acopladas, ela não é a única solução arquitetônica para esse problema. Por exemplo, a comunicação entre um modelo de exibição e uma exibição também pode ser obtida pelo mecanismo de associação e por meio de notificações de alteração de propriedade. Além disso, a comunicação entre dois modelos de exibição também pode ser obtida passando dados durante a navegação.

No aplicativo móvel eShopOnContainers, MessagingCenter é usado para atualizar na interface do usuário em resposta a uma ação que ocorre em outra classe. Portanto, as mensagens são publicadas no thread da interface do usuário, com os assinantes recebendo a mensagem no mesmo thread.

Dica

Realizar marshaling para o thread da interface do usuário ao executar atualizações da interface do usuário. Se uma mensagem enviada de um thread em segundo plano for necessária para atualizar a interface do usuário, processe a mensagem no thread da interface do usuário no assinante chamando o método Device.BeginInvokeOnMainThread.

Para obter mais informações sobre MessagingCenter, consulte MessagingCenter.

Definindo uma mensagem

MessagingCenter as mensagens são cadeias de caracteres usadas para identificar mensagens. O exemplo de código a seguir mostra as mensagens definidas no aplicativo móvel eShopOnContainers:

public class MessageKeys  
{  
    // Add product to basket  
    public const string AddProduct = "AddProduct";  

    // Filter  
    public const string Filter = "Filter";  

    // Change selected Tab programmatically  
    public const string ChangeTab = "ChangeTab";  
}

Neste exemplo, as mensagens são definidas usando constantes. A vantagem dessa abordagem é que ela fornece suporte para a segurança do tipo durante a compilação e a refatoração.

Publicando uma mensagem

Os publicadores notificam os assinantes de uma mensagem com uma das sobrecargas MessagingCenter.Send. O exemplo de código a seguir demonstra a publicação da mensagem AddProduct:

MessagingCenter.Send(this, MessageKeys.AddProduct, catalogItem);

Neste exemplo, o Send método especifica três argumentos:

  • O primeiro argumento especifica a classe do remetente. A classe do remetente deve ser especificada por quaisquer assinantes que desejam receber a mensagem.
  • O segundo argumento especifica a mensagem.
  • O terceiro argumento especifica os dados de conteúdo a serem enviados ao assinante. Nesse caso, os dados de conteúdo são uma CatalogItem instância .

O método Send publicará a mensagem, bem como os dados de conteúdo, usando uma abordagem do tipo “disparar e esquecer”. Portanto, a mensagem é enviada mesmo quando não há assinantes registrados para recebê-la. Nessa situação, a mensagem enviada é ignorada.

Observação

O método MessagingCenter.Send pode usar parâmetros genéricos para controlar como as mensagens são entregues. Portanto, várias mensagens que compartilham uma identidade de mensagem, mas enviam tipos de dados de conteúdo diferentes, podem ser recebidas por diferentes assinantes.

Assinando uma mensagem

Os assinantes podem se registrar para receber uma mensagem usando uma das sobrecargas MessagingCenter.Subscribe. O exemplo de código a seguir demonstra como o aplicativo móvel eShopOnContainers assina e processa a AddProduct mensagem:

MessagingCenter.Subscribe<CatalogViewModel, CatalogItem>(  
    this, MessageKeys.AddProduct, async (sender, arg) =>  
{  
    BadgeCount++;  

    await AddCatalogItemAsync(arg);  
});

Neste exemplo, o Subscribe método assina a AddProduct mensagem e executa um delegado de retorno de chamada em resposta ao recebimento da mensagem. Esse representante de retorno de chamada, especificado como uma expressão lambda, executa o código que atualiza a interface do usuário.

Dica

Considere usar dados de carga imutáveis. Não tente modificar os dados de conteúdo de dentro de um delegado de retorno de chamada porque vários threads podem estar acessando os dados recebidos simultaneamente. Nesse cenário, os dados de conteúdo devem ser imutáveis para evitar erros de simultaneidade.

Um assinante pode não precisar manipular todas as instâncias de uma mensagem publicada, e isso pode ser controlado pelos argumentos de tipo genérico especificados no método Subscribe. Neste exemplo, o assinante receberá AddProduct apenas mensagens enviadas da CatalogViewModel classe , cujos dados de conteúdo são uma CatalogItem instância.

Cancelar a assinatura de uma mensagem

Os assinantes podem cancelar a assinatura de mensagens que não desejam mais receber. Isso é feito com uma das sobrecargas MessagingCenter.Unsubscribe, conforme demonstrado no seguinte exemplo de código:

MessagingCenter.Unsubscribe<CatalogViewModel, CatalogItem>(this, MessageKeys.AddProduct);

Neste exemplo, a Unsubscribe sintaxe do método reflete os argumentos de tipo especificados ao assinar para receber a AddProduct mensagem.

Resumo

A Xamarin.FormsMessagingCenter classe implementa o padrão publish-subscribe, permitindo a comunicação baseada em mensagem entre componentes inconvenientes para vincular por referências de objeto e tipo. Esse mecanismo permite que publicadores e assinantes se comuniquem sem uma referência entre eles, ajudando a reduzir as dependências entre os componentes, permitindo também que os componentes sejam desenvolvidos e testados independentemente.