Comunicazioni tra componenti ad accoppiamento debole
Nota
Questo eBook è stato pubblicato nella primavera del 2017 e non è stato aggiornato da allora. C'è molto nel libro che rimane prezioso, ma alcuni dei materiali sono obsoleti.
Il modello di pubblicazione-sottoscrizione è un modello di messaggistica in cui i server di pubblicazione inviano messaggi senza conoscere i ricevitori, noti come sottoscrittori. In modo analogo, i sottoscrittori sono in ascolto di messaggi specifici, senza conoscere i server di pubblicazione.
Gli eventi in .NET implementano il modello publish-subscribe e sono l'approccio più semplice e semplice per un livello di comunicazione tra componenti se non è necessario l'accoppiamento libero, ad esempio un controllo e la pagina che lo contiene. Tuttavia, le durate del server di pubblicazione e del sottoscrittore sono accoppiate l'una all'altra tramite riferimenti a oggetti e il tipo di sottoscrittore deve avere un riferimento al tipo di server di pubblicazione. Ciò può creare problemi di gestione della memoria, soprattutto quando sono presenti oggetti di breve durata che sottoscrivono un evento di un oggetto statico o di lunga durata. Se il gestore eventi non viene rimosso, il sottoscrittore verrà mantenuto attivo dal riferimento a esso nel server di pubblicazione e questo impedirà o ritarderà l'operazione di Garbage Collection del sottoscrittore.
Introduzione a MessagingCenter
La Xamarin.FormsMessagingCenter
classe implementa il modello publish-subscribe, consentendo la comunicazione basata su messaggi tra i componenti non convenienti da collegare tramite riferimenti a oggetti e tipi. Questo meccanismo consente ai server di pubblicazione e ai sottoscrittori di comunicare senza avere un riferimento diretto l'uno all'altro, contribuendo a ridurre le dipendenze tra i componenti e consentendo lo sviluppo e il test indipendente di tali componenti.
La classe MessagingCenter
fornisce una funzionalità di pubblicazione-sottoscrizione multicast. Ciò significa che possono essere presenti più server di pubblicazione che pubblicano un singolo messaggio e che possono essere presenti più sottoscrittori in ascolto dello stesso messaggio. La figura 4-1 illustra questa relazione:
Figura 4-1: Funzionalità di pubblicazione-sottoscrizione multicast
I server di pubblicazione inviano i messaggi usando il metodo MessagingCenter.Send
, mentre i sottoscrittori sono in ascolto dei messaggi usando il metodo MessagingCenter.Subscribe
. I sottoscrittori possono inoltre annullare la sottoscrizione dei messaggi, se necessario, con il metodo MessagingCenter.Unsubscribe
.
Internamente, la classe MessagingCenter
usa riferimenti deboli. Ciò significa che non manterrà gli oggetti attivi e consentirà di sottoporli a Garbage Collection, quindi dovrebbe essere necessario annullare la sottoscrizione di un messaggio solo quando una classe non vuole più ricevere il messaggio.
L'app per dispositivi mobili eShopOnContainers usa la MessagingCenter
classe per comunicare tra componenti ad accoppiamento libero. L'app definisce tre messaggi:
- Il
AddProduct
messaggio viene pubblicato dallaCatalogViewModel
classe quando un elemento viene aggiunto al carrello acquisti. In cambio, laBasketViewModel
classe sottoscrive il messaggio e incrementa il numero di articoli nel carrello acquisti in risposta. Inoltre, laBasketViewModel
classe annulla anche la sottoscrizione a questo messaggio. - Il
Filter
messaggio viene pubblicato dallaCatalogViewModel
classe quando l'utente applica un filtro di marca o tipo agli elementi visualizzati dal catalogo. In cambio, laCatalogView
classe sottoscrive il messaggio e aggiorna l'interfaccia utente in modo che vengano visualizzati solo gli elementi che corrispondono ai criteri di filtro. - Il
ChangeTab
messaggio viene pubblicato dallaMainViewModel
classe quandoCheckoutViewModel
passa allaMainViewModel
seguente creazione e invio di un nuovo ordine. In cambio, laMainView
classe sottoscrive il messaggio e aggiorna l'interfaccia utente in modo che la scheda Profilo personale sia attiva, per mostrare gli ordini dell'utente.
Nota
Sebbene la classe consenta la MessagingCenter
comunicazione tra classi ad accoppiamento libero, non offre l'unica soluzione architetturale a questo problema. Ad esempio, la comunicazione tra un modello di visualizzazione e una visualizzazione può essere ottenuta anche dal motore di associazione e tramite notifiche delle modifiche delle proprietà. Inoltre, è possibile ottenere la comunicazione tra due modelli di visualizzazione passando i dati durante la navigazione.
Nell'app MessagingCenter
per dispositivi mobili eShopOnContainers viene usato per eseguire l'aggiornamento nell'interfaccia utente in risposta a un'azione eseguita in un'altra classe. Pertanto, i messaggi vengono pubblicati nel thread dell'interfaccia utente, con i sottoscrittori che ricevono il messaggio sullo stesso thread.
Suggerimento
Effettuare il marshalling al thread dell'interfaccia utente durante l'esecuzione di aggiornamenti dell'interfaccia utente. Se per aggiornare l'interfaccia utente è necessario un messaggio inviato da un thread in background, elaborare il messaggio nel thread dell'interfaccia utente nel sottoscrittore richiamando il metodo Device.BeginInvokeOnMainThread
.
Per altre informazioni su MessagingCenter
, vedere MessagingCenter.
Definizione di un messaggio
MessagingCenter
i messaggi sono stringhe usate per identificare i messaggi. L'esempio di codice seguente mostra i messaggi definiti nell'app per dispositivi mobili 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";
}
In questo esempio i messaggi vengono definiti usando costanti. Il vantaggio di questo approccio è che offre supporto per la sicurezza dei tipi in fase di compilazione e il refactoring.
Pubblicazione di un messaggio
I server di pubblicazione notificano un messaggio ai sottoscrittori con uno degli overload di MessagingCenter.Send
. Nell'esempio di codice seguente viene mostrata la pubblicazione del messaggio AddProduct
:
MessagingCenter.Send(this, MessageKeys.AddProduct, catalogItem);
In questo esempio il Send
metodo specifica tre argomenti:
- Il primo argomento specifica la classe sender. La classe sender deve essere specificata da tutti i sottoscrittori che desiderano ricevere il messaggio.
- Il secondo argomento specifica il messaggio.
- Il terzo argomento specifica i dati del payload da inviare al sottoscrittore. In questo caso, i dati del payload sono un'istanza
CatalogItem
di .
Il metodo Send
pubblicherà il messaggio e i relativi dati di payload usando un approccio "fire-and-forget". Il messaggio viene quindi inviato anche se non sono presenti sottoscrittori registrati per la ricezione del messaggio. In questa situazione, il messaggio inviato viene ignorato.
Nota
Il MessagingCenter.Send
metodo può usare parametri generici per controllare la modalità di recapito dei messaggi. Pertanto, più messaggi che condividono un'identità del messaggio, ma che inviano tipi di dati payload diversi possono essere ricevuti da sottoscrittori diversi.
Sottoscrizione a un messaggio
I sottoscrittori possono registrarsi per ricevere un messaggio usando uno degli overload di MessagingCenter.Subscribe
. L'esempio di codice seguente illustra come l'app per dispositivi mobili eShopOnContainers sottoscrive e elabora il AddProduct
messaggio:
MessagingCenter.Subscribe<CatalogViewModel, CatalogItem>(
this, MessageKeys.AddProduct, async (sender, arg) =>
{
BadgeCount++;
await AddCatalogItemAsync(arg);
});
In questo esempio il Subscribe
metodo sottoscrive il AddProduct
messaggio ed esegue un delegato di callback in risposta alla ricezione del messaggio. Questo delegato di callback, specificato come espressione lambda, esegue il codice che aggiorna l'interfaccia utente.
Suggerimento
Prendere in considerazione l'uso di dati di payload non modificabili. Non tentare di modificare i dati del payload dall'interno di un delegato di callback perché diversi thread potrebbero accedere contemporaneamente ai dati ricevuti. In questo scenario, i dati del payload devono essere non modificabili per evitare errori di concorrenza.
Tramite gli argomenti di tipo generico specificati nel metodo Subscribe
, è possibile controllare se un sottoscrittore deve gestire ogni istanza di un messaggio pubblicato. In questo esempio, il sottoscrittore riceverà AddProduct
solo messaggi inviati dalla classe , i CatalogViewModel
cui dati di payload sono un'istanza CatalogItem
di .
Annullamento della sottoscrizione da un messaggio
I sottoscrittori possono annullare la sottoscrizione dei messaggi che non vogliono più ricevere A tale scopo, è necessario usare uno degli overload MessagingCenter.Unsubscribe
, come illustrato nell'esempio di codice seguente:
MessagingCenter.Unsubscribe<CatalogViewModel, CatalogItem>(this, MessageKeys.AddProduct);
In questo esempio la sintassi del Unsubscribe
metodo riflette gli argomenti di tipo specificati durante la sottoscrizione per ricevere il AddProduct
messaggio.
Riepilogo
La Xamarin.FormsMessagingCenter
classe implementa il modello publish-subscribe, consentendo la comunicazione basata su messaggi tra i componenti non convenienti da collegare tramite riferimenti a oggetti e tipi. Questo meccanismo consente ai server di pubblicazione e ai sottoscrittori di comunicare senza avere un riferimento diretto l'uno all'altro, contribuendo a ridurre le dipendenze tra i componenti e consentendo lo sviluppo e il test indipendente di tali componenti.