English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية
Dieser Artikel beschreibt ein Beispiel für das Observer-Pattern in der Android-Programmierung und Design-Patterns. Hiermit möchte ich allen etwas zur Verfügung stellen, was ich als Referenz teile, wie folgt:
Eins: Einführung
Das Observer-Pattern ist ein sehr häufig verwendetes Muster, das in GUI-Systemen, Subscription-Publishing-Systemen am häufigsten verwendet wird. Eine wichtige Funktion dieses Musters ist die Entkopplung, die das Beobachtete und den Beobachter entkoppelt, so dass ihre Abhängigkeit geringer wird, ja sogar ohne Abhängigkeit. Wenn man von GUI-Systemen spricht, ist die UI des Anwendungsprogramms leicht veränderlich, insbesondere im frühen Stadium, wenn sich die Geschäftslogik oder die Anforderungen des Produkts ändern, ändert sich auch die Benutzeroberfläche des Anwendungsprogramms regelmäßig, aber die Geschäftslogik ändert sich nicht grundlegend. In diesem Fall benötigt das GUI-System ein Mechanismus, um dieser Situation zu begegnen, so dass die UI-Schicht von der spezifischen Geschäftslogik entkoppelt wird und das Observer-Pattern kommt dann zum Einsatz.
Zwei: Definition
Definition einer eindeutigen Abhängigkeitsbeziehung zwischen Objekten, so dass每当 ein Objekt seinen Zustand ändert, alle abhängigen Objekte benachrichtigt werden und automatisch aktualisiert werden.
Drei: Anwendungsgebiete
Szenarien mit verbundenem Verhalten, wobei zu beachten ist, dass verbundenes Verhalten trennbar ist und nicht eine „Kombination“-Beziehung darstellt.
Szenarien für mehrstufige Auslöser von Ereignissen.
Szenarien für den Nachrichtenaustausch zwischen Systemen, wie z.B. die Verarbeitungsmethoden von Nachrichtenqueues und Event-Bus.
Vier: UML-Klassendiagramm des Observer-Patterns
UML-Klassendiagramm:
Rollenbeschreibung:
Betreff: Abstrakter Thema, das auch die Rolle des Beobachteten (Observable) darstellt. Die Rolle des abstrakten Themas speichert alle Referenzen der Beobachterobjekte in einer Sammlung und jedes Thema kann eine beliebige Anzahl von Beobachtern haben. Das abstrakte Thema bietet eine Schnittstelle, um Beobachterobjekte hinzuzufügen und zu entfernen.
ConcreteSubject: Konkreter Thema, der relevante Zustände in das Objekt der konkreten Beobachter speichert und alle registrierten Beobachter benachrichtigt, wenn der innere Zustand des konkreten Themas geändert wird. Die Rolle des konkreten Themas wird auch als Rolle des konkreten Beobachteten (ConcreteObservable) bezeichnet.
Observer: Abstrakte Beobachterklasse, die die abstrakte Klasse der Beobachter ist, die ein Update-Interface definiert, um sich selbst zu aktualisieren, wenn eine Änderungsbenachrichtigung des Themas erhalten wird.
ConcreteObserver: Konkrete Beobachterklasse, die das Update-Interface der abstrakten Beobachterrolle implementiert, um ihren eigenen Zustand zu aktualisieren, wenn der Zustand des Themas geändert wird.
V
Hier ist ein Beispiel für das Verfolgen einer TV-Serie: Um keine neuen Folgen zu verpassen, abonnieren oder folgen wir dieser TV-Serie. Wenn die TV-Serie aktualisiert wird, werden wir sie sofort gesendet. Hier wird eine einfache Implementierung vorgestellt.
Abstrakte Beobachterklasse:
/** * Abstrakte Beobachterklasse, definiert eine Schnittstelle für alle konkreten Beobachter, um sich selbst zu aktualisieren, wenn eine Benachrichtigung erhalten wird */ public interface Observer { /** * Es gibt Updates * * @param message Nachricht */ public void update(String message); }
Abstrakte beobachtete Klasse:
/** * Abstrakte beobachtete Klasse */ public interface Observable { /** * Nachricht senden * * @param message Inhalt */ void push(String message); /** * Abonnement * * @param observer Abonnent */ void register(Observer observer); }
Konkrete Beobachterklasse:
/** * Konkrete Beobachterklasse, auch bekannt als Abonnent */ public class User implements Observer { @Override public void update(String message) { System.out.println(name + ", + message + "Aktualisiert!"); } // Name des Abonnenten private String name; public User(String name) { this.name = name; } }
Konkrete beobachtete Klasse:
/** * Konkrete beobachtete Klasse, auch bekannt als abonnierte Sendung */ public class Teleplay implements Observable{ private List<Observer> list = new ArrayList<Observer>();//Speicherung der Abonnenten @Override public void push(String message) { for(Observer observer:list){ observer.update(message); } } @Override public void register(Observer observer) { list.add(observer); } }
Umsetzung:
public class Client { public static void main(String[] args) { //Beobachteter, hier ist das abonnierte Fernsehspiel des Benutzers Teleplay teleplay = new Teleplay(); //Beobachter, hier sind die abonnierten Benutzer User user1 = new User("Xiaoming"); User user2 = new User("Xiaoguang"); User user3 = new User("Xiaolan"); //Abonnement teleplay.register(user1); teleplay.register(user2); teleplay.register(user3); //Neue Nachrichten推送 teleplay.push("xxx-Fernsehspiel"); } }
Ergebnis:
Xiaoming, das xxx-Fernsehspiel wurde aktualisiert! Xiaoguang, das xxx-Fernsehspiel wurde aktualisiert! Xiaolan, das xxx-Fernsehspiel wurde aktualisiert!
Aus dem obigen Code lässt sich erkennen, dass ein einzuholendes Nachrichten推送 wurde implementiert, wobei die Nachrichten推送 sind abhängig von Observer und Observable, diesen abstrakten Klassen, und User und Teleplay sind vollständig voneinander entkoppelt, was die Flexibilität und Erweiterbarkeit des Abonnementsystems gewährleistet.
Sechstens, das Beobachtermuster in der Android-Quellcode
1、BaseAdapter
BaseAdapter ist für viele von uns vertraut, wir erben es in den ListViews. Lassen Sie uns eine einfache Analyse durchführen.
BaseAdapter-Teilcode:
public abstract class BaseAdapter implements ListAdapter, SpinnerAdapter { //Datenbank-Beobachter private final DataSetObservable mDataSetObservable = new DataSetObservable(); public boolean hasStableIds() { return false; } public void registerDataSetObserver(DataSetObserver observer) { mDataSetObservable.registerObserver(observer); } public void unregisterDataSetObserver(DataSetObserver observer) { mDataSetObservable.unregisterObserver(observer); } /** * wenn sich der Daten set ändert, alle Beobachter benachrichtigen */ public void notifyDataSetChanged() { mDataSetObservable.notifyChanged(); } }
Sehen Sie sich die Methode mDataSetObservable.notifyChanged() an:
public class DataSetObservable extends Observable<DataSetObserver> { /** * ruft {@link DataSetObserver#onChanged} bei jedem Beobachter auf. * Wird aufgerufen, wenn sich der Inhalt des Daten sets geändert hat. Der Empfänger * den nächsten Mal, wenn es das Daten set abfragt, neue Inhalte erhalten wird. */ public void notifyChanged() { synchronized(mObservers) { // da onChanged() vom App implementiert wird, könnte es alles tun, einschließlich // es sich selbst von {@link mObservers} entfernen - das könnte Probleme verursachen, wenn // ein Iterator wird auf die ArrayList {@link mObservers} verwendet. // um solche Probleme zu vermeiden, durch die Liste im umgekehrten Reihenfolge zu marschieren. for (int i = mObservers.size() - 1; i >= 0; i--) { mObservers.get(i).onChanged(); } } } }
Es kann ersehen werden, dass in mDataSetObservable.notifyChanged() alle Beobachter durchsucht werden und ihre onChanged()-Methode aufgerufen wird, um den Beobachtern mitzuteilen, was passiert ist.
Dann wie kommt der Beobachter her, das ist die setAdapter-Methode, der Code ist wie folgt:
@Override public void setAdapter(ListAdapter adapter) { if (mAdapter != null && mDataSetObserver != null) { mAdapter.unregisterDataSetObserver(mDataSetObserver); } resetList(); mRecycler.clear(); if (mHeaderViewInfos.size() > 0 || mFooterViewInfos.size() > 0) { mAdapter = new HeaderViewListAdapter(mHeaderViewInfos, mFooterViewInfos, adapter); } else { mAdapter = adapter; } mOldSelectedPosition = INVALID_POSITION; mOldSelectedRowId = INVALID_ROW_ID; // AbsListView#setAdapter wird den Zustand der Auswahlmodi aktualisieren. super.setAdapter(adapter); if (mAdapter != null) { mAreAllItemsSelectable = mAdapter.areAllItemsEnabled(); mOldItemCount = mItemCount; mItemCount = mAdapter.getCount(); checkFocus(); mDataSetObserver = new AdapterDataSetObserver(); mAdapter.registerDataSetObserver(mDataSetObserver);//Registrierung des Beobachters ......ausgelassen } }
AdapterDataSetObserver wird in der Elternklasse AbsListView von ListView definiert und ist ein Datenbanksatz-Beobachter, Code:
class AdapterDataSetObserver extends AdapterView<ListAdapter>.AdapterDataSetObserver { @Override public void onChanged() { super.onChanged(); if (mFastScroller != null) { mFastScroller.onSectionsChanged(); } } @Override public void onInvalidated() { super.onInvalidated(); if (mFastScroller != null) { mFastScroller.onSectionsChanged(); } } }
Es wird von dem elterlichen AdapterView, der von AbsListView abgeleitet ist, AdapterDataSetObserver verwendet, der Code ist wie folgt :
class AdapterDataSetObserver extends DataSetObserver { private Parcelable mInstanceState = null; // Wie bereits erwähnt, wird bei der Aufrufung von Adapter.notifyDataSetChanged() die onChanged-Methode aller Beobachter aufgerufen, der Kern der Implementierung befindet sich hier @Override public void onChanged() { mDataChanged = true; mOldItemCount = mItemCount; // Zahl der Daten im Adapter erhalten mItemCount = getAdapter().getCount(); // Detect the case where a cursor that was previously invalidated has // wurde mit neuen Daten neu gefüllt. if (AdapterView.this.getAdapter().hasStableIds() && mInstanceState != null && mOldItemCount == 0 && mItemCount > 0) { AdapterView.this.onRestoreInstanceState(mInstanceState); mInstanceState = null; } else { rememberSyncState(); } checkFocus(); // Neu Anordnung der AdapterView-Komponenten wie ListView, GridView und ähnlichem requestLayout(); } // Code wird weggelassen public void clearSavedState() { mInstanceState = null; } }
Wenn die Daten von ListView geändert werden, wird die Funktion notifyDataSetChanged des Adapters aufgerufen. Diese Funktion ruft wiederum die Funktion notifyChanged des DataSetObservable auf, die alle Beobachter (AdapterDataSetObserver) auf die Methode onChanged aufruft. Dies ist ein Observer-Pattern!
Kapitel VII: Zusammenfassung
Vorteile:
Die Observer und das Beobachtete sind abstrakt gekoppelt und sollten auf Änderungen im Geschäft reagieren.
Erhöhung der Flexibilität und Erweiterbarkeit des Systems.
Nachteile:
Bei der Verwendung des Observer-Patterns müssen einige Überlegungen zur Entwicklungs- und Laufzeiteffizienz angestellt werden. In der Anwendung sind ein Beobachter und mehrere Beobachter enthalten, und die Entwicklung und das Debugging sind relativ komplex. Und in Java wird die Benachrichtigung der Nachrichten in der Regel in der Reihenfolge ausgeführt. Wenn ein Beobachter hängt, kann dies die Gesamtleistung beeinträchtigen. In diesem Fall wird in der Regel eine asynchrone Implementierung verwendet.
Interessierte Leser, die mehr über Android-Inhalte erfahren möchten, können die Themen dieser Website überprüfen: 'Android-Entwicklung für Anfänger und Fortgeschrittene', 'Android-Debugging-Techniken und häufige Problembehebung', 'Zusammenfassung der Verwendung von Android-Grundkomponenten', 'Zusammenfassung der Techniken für Android-Views', 'Zusammenfassung der Techniken für Android-Layouts' und 'Zusammenfassung der Verwendung von Android-Kontrollen'.
Ich hoffe, dass die in diesem Artikel beschriebenen Inhalte allen bei der Android-Programmierung helfen.
Erklärung: Der Inhalt dieses Artikels wurde aus dem Internet übernommen und gehört dem Urheberrechtsinhaber. Der Inhalt wurde von Internetnutzern freiwillig bereitgestellt und hochgeladen. Diese Website besitzt keine Eigentumsrechte und hat den Inhalt nicht manuell bearbeitet. Sie trägt auch keine rechtlichen Verantwortlichkeiten. Wenn Sie verdächtige Urheberrechtsinhalte finden, sind Sie herzlich eingeladen, eine E-Mail an notice#w zu senden.3codebox.com (Bitte ersetzen Sie # durch @, wenn Sie eine Meldung senden, und fügen Sie relevante Beweise bei. Bei nachgewiesener Infringement wird dieser Inhalt sofort gelöscht.)