Condividi tramite


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:

Multicast publish-subscribe functionality

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 dalla CatalogViewModel classe quando un elemento viene aggiunto al carrello acquisti. In cambio, la BasketViewModel classe sottoscrive il messaggio e incrementa il numero di articoli nel carrello acquisti in risposta. Inoltre, la BasketViewModel classe annulla anche la sottoscrizione a questo messaggio.
  • Il Filter messaggio viene pubblicato dalla CatalogViewModel classe quando l'utente applica un filtro di marca o tipo agli elementi visualizzati dal catalogo. In cambio, la CatalogView 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 dalla MainViewModel classe quando CheckoutViewModel passa alla MainViewModel seguente creazione e invio di un nuovo ordine. In cambio, la MainView 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.