Observer model
A one-to-many dependency before defining an object so that when an object changes state, all objects that depend on that object are notified and updated automatically.
Usage scenarios
- Associated behavior scenarios. Associative behavior is separable, not a “composite” relationship
- Multi-level event triggering scenario
- Message interaction scenarios across systems. For example, the processing mechanism of message queue event bus
Structure and UML diagrams
- An Observable role stores references to all observers in a collection. Each theme can have any number of observers. An abstract theme provides an interface to add/remove observer objects.
- ConcreteSubject- Concrete Topic: Aka concrete observed, this object stores the group state into a concrete observer object, notifying all registered observers when the internal state of a concrete topic changes.
- Observer- an abstract Observer; The observer abstract class defines an update interface that allows you to change yourself when notified of changes to the topic.
- ConcreteSubject- Concrete observer; An update interface defined by the abstract observer role is implemented to update the state of the topic itself when the state changes.
A simple example
If we subscribe to the blog of a certain platform, we will inform our subscribers of the new blog through email and other means. I’ll use this as an example of a simple observer pattern abstract theme:
// Abstract the Subject role, Subject: observed
public abstract class Blog {
protected final ArrayList<User> mObservers = new ArrayList();
public void addUser(User user){
mObservers.add(user);
}
public void removeUser(User user){
mObservers.remove(user);
}
public void removeAll(a){ mObservers.clear(); }}Copy the code
Specific topics:
// Concrete theme role, ConcreteSubject: Concrete observed
public class ConcreteBlog extends Blog{
public ConcreteBlog(a) {
// TODO Auto-generated constructor stub
}
public void notifyChanged(String str){
for(int i=mObservers.size()-1; i>=0; i--){ mObservers.get(i).update(str); }}}Copy the code
Abstract observer:
// Abstract the observer role
public abstract class User {
public void update(String str) {}}Copy the code
Specific observer:
public class ConcreteUser extends User {
@Override
public void update(String str) { System.out.println(str); }}Copy the code
Use:
public class Client {
public Client(a) {
// TODO Auto-generated constructor stub
}
public static void main(String[] args) {
// Create the observed
ConcreteBlog blog=new ConcreteBlog();
// Create an observer
ConcreteUser user1=new ConcreteUser();
ConcreteUser user2=new ConcreteUser();
ConcreteUser user3=new ConcreteUser();
// Register the observer to the observer list of the observable
blog.addUser(user1);
blog.addUser(user2);
blog.addUser(user3);
blog.notifyChanged("Blog post, check it out!"); }}}Copy the code
The above content is excerpted from the Android source code design pattern analysis and combat.
RecyclerView source code in the observer mode
When using RecyclerView, we usually call notifyDataSetChanged() to update our view every time we update the RecyclerView data. So let’s start here, go to the source code and see how RecyclerView observer mode is implemented
public static abstract class Adapter<VH extends ViewHolder> {
// Define the observer
private final AdapterDataObservable mObservable = new AdapterDataObservable();
private boolean mHasStableIds = false;
public abstract VH onCreateViewHolder(ViewGroup parent, int viewType);
/ / to omit...
public void registerAdapterDataObserver(AdapterDataObserver observer) {
mObservable.registerObserver(observer);
}
public void unregisterAdapterDataObserver(AdapterDataObserver observer) {
mObservable.unregisterObserver(observer);
}
// Notify all observers
public final void notifyDataSetChanged(a) {
mObservable.notifyChanged();
}
Copy the code
Recyclerview. Adapter is the observer mode **, and notifyDataSetChanged() is the notifyDataSetChanged() method
static class AdapterDataObservable extends Observable<AdapterDataObserver> {
public boolean hasObservers(a) {
return! mObservers.isEmpty(); }// Call the onChanged() method on each observer to notify them that the observed has changed
public void notifyChanged(a) {
for (int i = mObservers.size() - 1; i >= 0; i--) { mObservers.get(i).onChanged(); }}public void notifyItemRangeChanged(int positionStart, int itemCount) {
notifyItemRangeChanged(positionStart, itemCount, null);
}
public void notifyItemRangeChanged(int positionStart, int itemCount, Object payload) {
for (int i = mObservers.size() - 1; i >= 0; i--) { mObservers.get(i).onItemRangeChanged(positionStart, itemCount, payload); }}/ / to omit...
Copy the code
Such a look, the original is in AdapterDataObservable. NotifyChanged () method to traverse all the observer, call their onChange () method to the notice. NotifyItemRangeChanged () notifies the observer with the same pattern.
Now that we know how an Observable is implemented, let’s find out where an Observer comes from. Recall that our RecyclerView associative data is usually achieved by calling setAdapter() method, so let’s go inside
public void setAdapter(Adapter adapter) {
// bail out if layout is frozen
setLayoutFrozen(false);
setAdapterInternal(adapter, false.true);
requestLayout();
}
Copy the code
Yi? This method passes adapter into the setAdapterInternal() method, so let’s follow through. The observer must be registered in the requestLayout() method that is then called to redraw the View.
RecyclerViewDataObserver RecyclerViewDataObserver RecyclerViewDataObserver
private final RecyclerViewDataObserver mObserver = new RecyclerViewDataObserver();
private void setAdapterInternal(Adapter adapter, boolean compatibleWithPrevious,
boolean removeAndRecycleViews) {
If an adapter already exists, unregister the observer of the adapter object
if(mAdapter ! =null) {
mAdapter.unregisterAdapterDataObserver(mObserver);
mAdapter.onDetachedFromRecyclerView(this);
}
if(! compatibleWithPrevious || removeAndRecycleViews) { removeAndRecycleViews(); } mAdapterHelper.reset();final Adapter oldAdapter = mAdapter;
mAdapter = adapter;
if(adapter ! =null) {
// Register the observer with the Adapter, essentially registering the observer with the AdapterDataObservable
adapter.registerAdapterDataObserver(mObserver);
adapter.onAttachedToRecyclerView(this);
}
if(mLayout ! =null) {
mLayout.onAdapterChanged(oldAdapter, mAdapter);
}
// Data update operation
mRecycler.onAdapterChanged(oldAdapter, mAdapter, compatibleWithPrevious);
mState.mStructureChanged = true;
/ / set the previous all known itemveiw invalid (ViewHolder logo FLAG_UPDATE | FLAG_INVALID)
markKnownViewsInvalid();
}
Copy the code
As we know from the above code, a RecyclerViewDataObserver will be built when setAdapter is set up, that is, the observer, and then register it in the observed -AdapterDataObservable. We found how the observed is associated with the observer, but specifically RecyclerViewDataObserver is what? How does the inside flash? In the code above, I mentioned the RecyclerViewDataObserver inheritance and AdapterDataObserver, so let’s first look at its parent class
public static abstract class AdapterDataObserver {
public void onChanged(a) {
// Do nothing
}
public void onItemRangeChanged(int positionStart, int itemCount) {
// do nothing
}
public void onItemRangeChanged(int positionStart, int itemCount, Object payload) {
// fallback to onItemRangeChanged(positionStart, itemCount) if app
// does not override this method.
onItemRangeChanged(positionStart, itemCount);
}
public void onItemRangeInserted(int positionStart, int itemCount) {
// do nothing
}
public void onItemRangeRemoved(int positionStart, int itemCount) {
// do nothing
}
public void onItemRangeMoved(int fromPosition, int toPosition, int itemCount) {
// do nothing}}Copy the code
The basic parent classes are empty methods with no concrete implementation. How does RecyclerViewDataObserver override the onChanged() method of its parent class
private class RecyclerViewDataObserver extends AdapterDataObserver {
RecyclerViewDataObserver() {
}
@Override
public void onChanged(a) {
assertNotInLayoutOrScroll(null);
mState.mStructureChanged = true;
//
setDataSetChangedAfterLayout();
if(! mAdapterHelper.hasPendingUpdates()) {// Rearrange the layoutrequestLayout(); }}.../ / to omit
}
Copy the code
To sum up, when the RecyclerView data changes, the Adapter notifyDataSetChanged() method is called, which in turn calls the AdapterDataObservable notifyChanged() method. This method in turn calls the onChanged() method of all observers, and RecyclerView is reconfigured in onChanged to refresh the RecyclerView interface. A complete observer pattern emerges.
conclusion
A RecyclerViewDataObserver was built when the Adapter was created, and registered into the Adapter when the setAdapter() was created. When we call notifyDataSetChanged(), we call the notifyChanged() method of the AdapterDataObservable, This method iterates through the onChanged() method of all observers, which calls RecyclerView to rearrange.