Udostępnij za pośrednictwem


Komunikacja między luźno sprzężonymi składnikami

Uwaga

Ta książka elektroniczna została opublikowana wiosną 2017 r. i od tego czasu nie została zaktualizowana. Jest wiele w książce, która pozostaje cenna, ale niektóre z materiałów są przestarzałe.

Wzorzec publikowania-subskrybowania to wzorzec obsługi komunikatów, w którym wydawcy wysyłają komunikaty bez znajomości jakichkolwiek odbiorców, znanych jako subskrybenci. Podobnie subskrybenci słuchają określonych komunikatów bez znajomości jakichkolwiek wydawców.

Zdarzenia na platformie .NET implementują wzorzec publikowania-subskrybowania i są najprostszym i najprostszym podejściem do warstwy komunikacji między składnikami, jeśli luźne sprzęganie nie jest wymagane, takie jak kontrolka i strona, która ją zawiera. Jednak okresy istnienia wydawcy i subskrybenta są powiązane ze sobą przez odwołania do obiektów, a typ subskrybenta musi mieć odwołanie do typu wydawcy. Może to powodować problemy z zarządzaniem pamięcią, zwłaszcza gdy istnieją obiekty krótkotrwałe, które subskrybują zdarzenie obiektu statycznego lub długotrwałego. Jeśli program obsługi zdarzeń nie zostanie usunięty, subskrybent będzie nadal aktywny przez odwołanie do niego w wydawcy, co uniemożliwi lub opóźni odzyskiwanie pamięci subskrybenta.

Wprowadzenie do programu MessagingCenter

Klasa Xamarin.FormsMessagingCenter implementuje wzorzec publikowania-subskrybowania, umożliwiając komunikację opartą na komunikatach między składnikami, które są niewygodne do łączenia według odwołań do obiektu i typu. Ten mechanizm umożliwia wydawcom i subskrybentom komunikowanie się bez odwołwania się do siebie, co pomaga zmniejszyć zależności między składnikami, jednocześnie umożliwiając niezależne opracowywanie i testowanie składników.

Klasa MessagingCenter zapewnia funkcję publikowania-subskrybowania multiemisji. Oznacza to, że może istnieć wiele wydawców, którzy publikują jeden komunikat, i może być wielu subskrybentów nasłuchujących tego samego komunikatu. Rysunek 4–1 ilustruje tę relację:

Multicast publish-subscribe functionality

Rysunek 4–1. Funkcja publikowania i subskrybowania multiemisji

Wydawcy wysyłają komunikaty przy użyciu MessagingCenter.Send metody , podczas gdy subskrybenci nasłuchują komunikatów przy użyciu MessagingCenter.Subscribe metody . Ponadto subskrybenci mogą również anulować subskrypcję wiadomości, jeśli jest to wymagane, za pomocą MessagingCenter.Unsubscribe metody .

MessagingCenter Wewnętrznie klasa używa słabych odwołań. Oznacza to, że nie będzie utrzymywać obiektów przy życiu i pozwoli im na zbieranie pamięci. W związku z tym należy anulować subskrypcję wiadomości tylko wtedy, gdy klasa nie chce już otrzymywać wiadomości.

Aplikacja mobilna eShopOnContainers używa MessagingCenter klasy do komunikowania się między luźno powiązanymi składnikami. Aplikacja definiuje trzy komunikaty:

  • Komunikat AddProduct jest publikowany przez klasę CatalogViewModel po dodaniu elementu do koszyka zakupów. W zamian BasketViewModel klasa subskrybuje komunikat i zwiększa liczbę elementów w koszyku zakupów w odpowiedzi. Ponadto BasketViewModel klasa anuluje również subskrypcję tej wiadomości.
  • Komunikat Filter jest publikowany przez klasę CatalogViewModel , gdy użytkownik stosuje filtr marki lub typu do elementów wyświetlanych z katalogu. W zamian klasa subskrybuje komunikat i aktualizuje interfejs użytkownika, CatalogView tak aby wyświetlane są tylko elementy zgodne z kryteriami filtrowania.
  • Komunikat ChangeTab jest publikowany przez klasę MainViewModel , gdy CheckoutViewModel przejdzie do MainViewModel następującego pomyślnego utworzenia i przesłania nowego zamówienia. W zamian MainView klasa subskrybuje komunikat i aktualizuje interfejs użytkownika, aby karta Mój profil był aktywna, aby wyświetlić zamówienia użytkownika.

Uwaga

MessagingCenter Klasa zezwala na komunikację między luźno powiązanymi klasami, ale nie oferuje jedynego rozwiązania architektonicznego dla tego problemu. Na przykład komunikacja między modelem widoku a widokiem może być również osiągana przez aparat powiązania i powiadomienia o zmianie właściwości. Ponadto komunikację między dwoma modelami widoków można również osiągnąć, przekazując dane podczas nawigacji.

W aplikacji MessagingCenter mobilnej eShopOnContainers służy do aktualizowania interfejsu użytkownika w odpowiedzi na akcję wykonywaną w innej klasie. W związku z tym komunikaty są publikowane w wątku interfejsu użytkownika, a subskrybenci odbierają komunikat w tym samym wątku.

Napiwek

Przeprowadzanie marshalingu do wątku interfejsu użytkownika podczas wykonywania aktualizacji interfejsu użytkownika. Jeśli do zaktualizowania interfejsu użytkownika jest wymagany komunikat wysyłany z wątku w tle, należy przetworzyć komunikat w wątku interfejsu użytkownika w subskrybentu, wywołując metodę Device.BeginInvokeOnMainThread .

Aby uzyskać więcej informacji na temat MessagingCenterprogramu , zobacz MessagingCenter.

Definiowanie komunikatu

MessagingCenter komunikaty to ciągi używane do identyfikowania komunikatów. Poniższy przykład kodu przedstawia komunikaty zdefiniowane w aplikacji mobilnej 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";  
}

W tym przykładzie komunikaty są definiowane przy użyciu stałych. Zaletą tego podejścia jest zapewnienie bezpieczeństwa i refaktoryzacji typu kompilacji.

Publikowanie komunikatu

Wydawcy powiadamiają subskrybentów o wiadomości z jednym MessagingCenter.Send z przeciążeń. W poniższym przykładzie kodu pokazano publikowanie komunikatu AddProduct :

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

W tym przykładzie Send metoda określa trzy argumenty:

  • Pierwszy argument określa klasę nadawcy. Klasa nadawcy musi być określona przez wszystkich subskrybentów, którzy chcą otrzymywać wiadomość.
  • Drugi argument określa komunikat.
  • Trzeci argument określa dane ładunku, które mają być wysyłane do subskrybenta. W takim przypadku dane ładunku są wystąpieniem CatalogItem .

Metoda Send opublikuje komunikat i jego dane ładunku przy użyciu podejścia fire-and-forget. W związku z tym wiadomość jest wysyłana nawet wtedy, gdy nie ma subskrybentów zarejestrowanych w celu odebrania wiadomości. W takiej sytuacji wysłana wiadomość jest ignorowana.

Uwaga

Metoda MessagingCenter.Send może użyć parametrów ogólnych do kontrolowania sposobu dostarczania komunikatów. W związku z tym wiele komunikatów, które współdzielą tożsamość wiadomości, ale wysyłają różne typy danych ładunku, mogą być odbierane przez różnych subskrybentów.

Subskrybowanie wiadomości

Subskrybenci mogą zarejestrować się, aby otrzymywać komunikat przy użyciu jednego z MessagingCenter.Subscribe przeciążeń. Poniższy przykład kodu pokazuje, jak aplikacja mobilna eShopOnContainers subskrybuje i przetwarza AddProduct komunikat:

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

    await AddCatalogItemAsync(arg);  
});

W tym przykładzie Subscribe metoda subskrybuje AddProduct komunikat i wykonuje delegat wywołania zwrotnego w odpowiedzi na odbieranie komunikatu. Ten delegat wywołania zwrotnego określony jako wyrażenie lambda wykonuje kod, który aktualizuje interfejs użytkownika.

Napiwek

Rozważ użycie niezmiennych danych ładunku. Nie próbuj modyfikować danych ładunku z poziomu delegata wywołania zwrotnego, ponieważ kilka wątków może uzyskiwać dostęp do odebranych danych jednocześnie. W tym scenariuszu dane ładunku powinny być niezmienne, aby uniknąć błędów współbieżności.

Subskrybent może nie musi obsługiwać każdego wystąpienia opublikowanego komunikatu i może być kontrolowany przez argumenty typu ogólnego określone w metodzie Subscribe . W tym przykładzie subskrybent będzie odbierał AddProduct tylko komunikaty wysyłane z CatalogViewModel klasy, której dane ładunku są wystąpieniem CatalogItem .

Anulowanie subskrypcji z wiadomości

Subskrybenci mogą anulować subskrypcję wiadomości, które nie chcą już otrzymywać. Jest to osiągane przy użyciu jednego MessagingCenter.Unsubscribe z przeciążeń, jak pokazano w poniższym przykładzie kodu:

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

W tym przykładzie składnia Unsubscribe metody odzwierciedla argumenty typu określone podczas subskrybowania odbierania komunikatu AddProduct .

Podsumowanie

Klasa Xamarin.FormsMessagingCenter implementuje wzorzec publikowania-subskrybowania, umożliwiając komunikację opartą na komunikatach między składnikami, które są niewygodne do łączenia według odwołań do obiektu i typu. Ten mechanizm umożliwia wydawcom i subskrybentom komunikowanie się bez odwołwania się do siebie, co pomaga zmniejszyć zależności między składnikami, jednocześnie umożliwiając niezależne opracowywanie i testowanie składników.