This article has participated in the good article call order activity, click to see: [back end, big front end double track submission, 20,000 yuan prize pool for you to challenge!]

Cognitive observer model

Let’s say there’s a newspaper, and its business is to publish newspapers, and now I’m a subscriber to the newspaper, and as soon as new papers come out, they’ll be delivered to me. Suddenly one day, I didn’t want to read the paper, so I canceled my subscription to the paper, so they wouldn’t deliver it to me, and of course as long as the paper was running, there would always be people like me subscribing and unsubscribing.

The example above is a typical observer pattern: publisher + subscriber = observer. But the name needs to be changed a bit. Publishers change it to “Subject” and subscribers to “Observer”.

To illustrate this more clearly, you can see that the observer pattern defines a one-to-many relationship between a set of objects, so that when an object changes, other dependencies are notified. Multiple observers depend on a topic, and as soon as the topic changes, the observers act on the notifications they receive.

Simple implementation

Say so much nonsense, or to practice out true knowledge ah ~

The class diagram

Look at the class diagram first. You can only write code with guidelines.

Character is introduced
  • The abstract Subject role stores references to all Observable objects in a collection. Each Subject can have any number of observers. The abstract Subject provides an interface for adding and removing observers
  • ConcreteSubject: A role that stores state in a ConcreteSubject to notify all registered observers of changes in the subject’s internal state. Also called a ConcreteObservable.
  • Observer: Abstract Observer that defines an update interface to be more detailed when notified of topic changes
  • ConcreteObserver: a ConcreteObserver that implements the interface defined by the abstract observer and updates itself when the topic changes state.

Simple implementation

  1. Abstract observer
//1. Interface Observe{void dispatch(); }Copy the code
  1. Abstract observed
Interface Subject{void removeObserve(Observe Observe); //2. void addObserve(Observe observe); void post(); }Copy the code
  1. Specific observer
Class MyObserve implements Observe{String name; //3. public MyObserve(String name) { this.name = name; } @override public void dispatch() {system.out.println (name+" receive notification "); }}Copy the code
  1. Specific observed
//4. Class MySubject implements Subject{ArrayList<Observe> list = new ArrayList<>(); @override public void post() {for(int I = 0; i<list.size(); i++){ list.get(i).dispatch(); @override public void addObserve(Observe Observe) {list.add(Observe); // Add observer @override public void addObserve(Observe Observe) {list.add(Observe); } @override public void removeObserve(Observe Observe) {list.remove(Observe); }}Copy the code

Test the

Public static void main(String[] args) {Observe observe1 = new MyObserve("1 observer "); Observe2 = new MyObserve(" observe2 "); Subject subject = new MySubject(); subject.addObserve(observe1); subject.addObserve(observe2); subject.post(); subject.removeObserve(observe2); subject.post(); }Copy the code

Take a look at the printout

Observer 1 receives notification Observer 2 receives notification Observer 1 receives notificationCopy the code

Use Java’s built-in observer pattern

Observer and Observable are built-in types in the JDK. An Observer is an abstract Observer role, and an Observable is an abstract subject role.

  1. Defining specific observers
Class MyObserve2 implements Observer{String name; public MyObserve2(String name) { this.name = name; } // The method to receive the notification, with parameter arg as the data sent by the subject, @override public void update(Observable, Object arg) {system.out.println (name+" Hello, hello ") The theme has been updated to read "+arg); }}Copy the code
  1. Defining specific topics
Class MySubject2 extends Observable{public void Post (String Content){setChanged(); // Notice all observers with the parameter notifyObservers(content); }}Copy the code
  1. Test the
public static void main(String[] args) { MySubject2 subject2 = new MySubject2(); MyObserve2 observe1 = new MyObserve2("1 observer "); MyObserve2 = new MyObserve2(" # 2 observer "); subject2.addObserver(observe1); subject2.addObserver(observe2); Subject2.post (" new message "); subject2.deleteObserver(observe2); Subject2.post (" another new message "); }Copy the code
  1. View the results
Hello observer number two, the topic has been updated with a new message. Hello observer number one, the topic has been updated with a new messageCopy the code

benefit

The observer pattern provides an object design that is loosely coupled between the subject and the observer. Everything about the Observer, the topic only knows that the Observer implements the interface (Observer). The topic does not need to know who the actual implementation class of the Observer is, what it does, and the details of its internals. And we can add new observers at any time. The only thing a topic depends on is a list of objects that implement the Observer interface, which can be added or removed at will. When a new type of observer appears, the topic code does not need to be modified. All you need to do is implement the observer interface in the new class and register as an observer. The topic does nothing but send notifications to all objects that implement the observer interface.

Changing one subject or observer does not affect the other; the two are loosely coupled and we are free to change them as long as the interface between them remains committed.

Usage scenarios in Android

RecyclerView uses observer mode

When we call notifyDataSetChanged(), we can refresh the list. How does this amazing design work? Let’s go to the source code to find out

  1. To realize the function of RecyclerView, it is necessary to set an adapter, the adapter needs to inherit the RecyclerView inner class, take a look at its internal implementation
public abstract static class Adapter<VH extends ViewHolder>{ private final AdapterDataObservable mObservable = new AdapterDataObservable(); . public final void notifyDataSetChanged() { mObservable.notifyChanged(); }... }Copy the code

NotifyDataSetChanged this method calls the notifyChanged method of mObservable, so what is an AdapterDataObservable

static class AdapterDataObservable extends Observable<AdapterDataObserver> { public boolean hasObservers() { return ! mObservers.isEmpty(); } public void notifyChanged() {// Call onChanged method for (int I = mobsers.size () -1; i >= 0; i--) { mObservers.get(i).onChanged(); }}...Copy the code

It inherits from Observable, which is the abstract subject class we talked about earlier. It’s not the Observable in the JDK, it’s the Android implementation, but the idea is the same. It’s a collection of observers. This collection of observers is managed by registering a registerObserver and unregisterObserver

public abstract class Observable<T> { protected final ArrayList<T> mObservers = new ArrayList<T>(); public void registerObserver(T observer) { if (observer == null) { throw new IllegalArgumentException("The observer is null."); } synchronized(mObservers) { if (mObservers.contains(observer)) { throw new IllegalStateException("Observer " + observer  + " is already registered."); } mObservers.add(observer); } } public void unregisterObserver(T observer) { if (observer == null) { throw new IllegalArgumentException("The observer is null."); } synchronized(mObservers) { int index = mObservers.indexOf(observer); if (index == -1) { throw new IllegalStateException("Observer " + observer + " was not registered."); } mObservers.remove(index); } } public void unregisterAll() { synchronized(mObservers) { mObservers.clear(); }}}Copy the code

AdapterDataObservable is a observed, and we have a reference to an AdapterDataObservable mObservable in the Adapter, The notifyChanged method of mObservable is called in the notifyDataSetChanged method, so what does notifyChanged do? Yes, walk through the observer mObservers and call their onChanged method. Let’s take a look at the implementation of the onChanged method

private class RecyclerViewDataObserver extends AdapterDataObserver { RecyclerViewDataObserver() { } @Override public void onChanged() { assertNotInLayoutOrScroll(null); mState.mStructureChanged = true; setDataSetChangedAfterLayout(); if (! mAdapterHelper.hasPendingUpdates()) { requestLayout(); }}... }Copy the code

The implementation of this class calls the requestLayout method to reapply the drawing process for the layout.

To here, the observer and the observer in RecyclerView have been found, so is in a what kind of circumstances, for registration and reconciliation? When we use RecyclerView, we need to set up a adapter for it, so start here

public void setAdapter(Adapter adapter) {
    // bail out if layout is frozen
    setLayoutFrozen(false);
    setAdapterInternal(adapter, false, true);
    requestLayout();
}
Copy the code

We see that the setAdadapter automatically calls requestLayout() to request that the layout be drawn. There is also a more important method, setAdapterInternal (), which we click on

private void setAdapterInternal(Adapter adapter, boolean compatibleWithPrevious, Boolean removeAndRecycleViews) {// Remove the old observer object if (mAdapter! = null) { mAdapter.unregisterAdapterDataObserver(mObserver); mAdapter.onDetachedFromRecyclerView(this); }... mAdapter = adapter; if (adapter ! = null) {/ / for the new adapter. The adapter registration observer registerAdapterDataObserver (mObserver); adapter.onAttachedToRecyclerView(this); } if (mLayout ! = null) { mLayout.onAdapterChanged(oldAdapter, mAdapter); } mRecycler.onAdapterChanged(oldAdapter, mAdapter, compatibleWithPrevious); mState.mStructureChanged = true; setDataSetChangedAfterLayout(); }Copy the code

Observer registered settlement tied is carried out in this method, through unregisterAdapterDataObserver and registerAdapterDataObserver these two methods to implement.

/ / solution to public void unregisterAdapterDataObserver (AdapterDataObserver observer) {mObservable. UnregisterObserver (observer);  }Copy the code
/ / registered public void registerAdapterDataObserver (AdapterDataObserver observer) {mObservable. RegisterObserver (observer); }Copy the code

These two methods ultimately need to be implemented through unregisterObserver and registerObserver of the mObservable observer. These two methods are familiar to you. That’s it for the RecyclerView observer mode. In addition to the observer mode used in RecyclerView, other places useful? Of course there is. The use of observer mode on Android is just too widespread. Let’s look at one more.

The observer pattern is used at LifeCycle

Through the above examples, it will be found that where the observer pattern is applied, it is particularly important to find the observer and the observed.

First of all, find out the related core classes:

  • Observed: lifecycleOwner
  • Observer: LifecycleObserver
  • Container for storing observers: LifecycleRegistry

LifeCycle is the LifecycleOwner, which has only one method

public interface LifecycleOwner {
    Lifecycle getLifecycle();
}
Copy the code

Android Support packages above 26 for fragments and AppCompatActivity already implement this interface by default, so they are also on the radar for LifeCycle. Look at the implementations in Fragments

public class Fragment implements ComponentCallbacks, OnCreateContextMenuListener, LifecycleOwner { LifecycleRegistry mLifecycleRegistry = new LifecycleRegistry(this); @Override public Lifecycle getLifecycle() { return mLifecycleRegistry; } void performCreate(Bundle savedInstanceState) { onCreate(savedInstanceState); mLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_CREATE); } void performStart() { onStart(); mLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_START); } void performResume() { onResume(); mLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_RESUME); } void performPause() { mLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_PAUSE); onPause(); } void performStop() { mLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_STOP); onStop(); } void performDestroy() { mLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_DESTROY); onDestroy(); }}Copy the code

What really acts as LifeCycle in Fragmnet is mLifecycleRegistry, which in turn inherits from LifeCycle

public abstract class Lifecycle { public abstract void addObserver(@NonNull LifecycleObserver observer); public abstract void removeObserver(@NonNull LifecycleObserver observer); public abstract State getCurrentState(); public enum Event { ON_CREATE, ON_START, ON_RESUME, ON_PAUSE, ON_STOP, ON_DESTROY, ON_ANY } public enum State { DESTROYED, INITIALIZED, CREATED, STARTED, RESUMED; public boolean isAtLeast(@NonNull State state) { return compareTo(state) >= 0; }}}Copy the code

LifeCycle defines the methods and enumerations for adding an observer, removing an Observer, fetching State, Event and State, which are implemented in LifecycleRegistry, its only implementation class. Specific implementation can go to the source code.

Finally, the LifecycleObserver is implemented in two ways:

  1. Implement the LifecycleObserver interface, add OnLifecycleEvent annotation to the related declaration cycle method, this scheme, according to the annotation using APT at compile time automatically generated GeneratedAdapter implementation class, only one method callMethods, The method is called back when the declaration period changes.
  2. The second approach is to implement the DefaultLifecycleObserver for Java8 and above, using the default keyword null for Java8 to implement all the methods of the FullLifecycleObserver

In either case, the onStateChanged method will be implemented because the observer’s onStateChanged method will eventually be invoked.

This concludes the core classes that LifeCycle relates to the observer pattern, although the internal implementation is more complex and needs further investigation.

conclusion

This article introduces several roles of the Observer pattern, and briefly implements it, and analyzes it from the Perspective of Android. Of course, there are many applications of the Observer pattern in Android, such as EventBus, Rxjava, LiveData, etc. More and more components are integrating the Observer pattern. It also illustrates the importance of the observer model. I hope reading this article inspires you.

The resources

  • Blog.csdn.net/c10WTiybQ1Y…
  • www.jianshu.com/p/1ee2af63c…
  • Head First design mode
  • Blog.csdn.net/verymrq/art…