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ę:
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 zamianBasketViewModel
klasa subskrybuje komunikat i zwiększa liczbę elementów w koszyku zakupów w odpowiedzi. PonadtoBasketViewModel
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
, gdyCheckoutViewModel
przejdzie doMainViewModel
następującego pomyślnego utworzenia i przesłania nowego zamówienia. W zamianMainView
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 MessagingCenter
programu , 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.