current position:Home>Android architect's road 13 observer mode of design mode

Android architect's road 13 observer mode of design mode

2022-01-28 15:07:21 Drizzle in winter

1、 Observer model concept

1.1 Introduce

When there is a one to many relationship between objects , Use observer mode (Observer Pattern). such as , When an object is modified , Will automatically notify its dependent objects . Observer model belongs to behavioral model .

1.2 Definition

Observer mode ( Also known as publishing - subscribe (Publish/Subscribe) Pattern , One of the behavioral patterns , It defines a one to many dependency , Have multiple observer objects listen to a topic object at the same time . When the state of the subject object changes , All observer objects will be notified , Enable them to automatically update themselves .

1.3 Use scenarios
  • When the data of an object is updated, other objects need to be notified , But this object doesn't want to form a tight coupling with the notified objects .
  • When an object's data is updated , This object needs to let other objects update their own data , But this object doesn't know how many objects need to update data .

2、 Observer mode UML Class diagram

 Observer mode UML Class diagram

The roles are as follows :

  • Abstract themes (Subject) : An abstract topic provides an interface , Observer objects can be added and removed , The abstract subject role is also called the abstract being observed (Observable) role .
  • Specific themes (ConcreteSubject) : Maintain a list of references to all specific observers , The relevant state is stored in the concrete observer object ; When the internal state of a specific topic changes , Notify all registered observers . The specific subject role is also called the specific observed (Concrete Observable) role .
  • Abstract observer (Observer) : Define an interface for all concrete observers ; Defined a update Method , Called when notified of the subject , This interface is called the update interface .
  • Concrete observer (ConcreteObserver) : Implement the update interface required by the abstract observer role , adopt update() Method reception ConcreteSubject The notice of , And make specific treatment . if necessary , The specific observer role can maintain a point ConcreteSubject References to objects ( be used for ConcreteSubject Transmission of status information ).

3、 Observer mode implementation

Subject:

public class AbstractSubject {

    /** *  Save registered observers  */
    private List<Observer> list = new ArrayList<>();

    /** *  Add observers  * @param observer */
    public void attach(Observer observer){
        list.add(observer);
    }

    public void detach(Observer observer){
        list.remove(observer);
    }

    public void notifyObservers(String content){
        for(Observer observer :list ){
            observer.update(content);
        }
    }
}
 Copy code 
ConcreteSubject:

public class ConcreteSubject extends AbstractSubject{
}
 Copy code 
Observer:

public interface Observer {

    /** *  Update interface  * @param state */
    public void update(String state);
}
 Copy code 
ConcreteObserver:

public class ConcreteObserver implements Observer{

    private String name;

    public ConcreteObserver(String name) {
        this.name = name;
    }

    @Override
    public void update(String content) {
         System.out.println(name+": "+content);
    }
}
 Copy code 
Client:

public class Client {
    public static void main(String[] args) {
        // Create an observed 
        ConcreteSubject subject = new ConcreteSubject();
        // Define an observer 
        Observer observer1 = new ConcreteObserver(" Observer one ");
        Observer observer2 = new ConcreteObserver(" Observer 2 ");
        Observer observer3 = new ConcreteObserver(" Observer three ");
        Observer observer4 = new ConcreteObserver(" Observer IV ");
        // The observer observes the observed 
        subject.attach(observer1);
        subject.attach(observer2);
        subject.attach(observer3);
        subject.attach(observer4);

        // An observer cancels observation 
        subject.detach(observer2);

        // The observer began to move 
        subject.notifyObservers("  Little bear updated the article  ");
    }
}
 Copy code 

Results output :


 Observer one :   Little bear updated the article  
 Observer three :   Little bear updated the article  
 Observer IV :   Little bear updated the article  
 Copy code 

4、Android Pattern implementation in source code

In the past , The most common control we use is ListView 了 , and ListView The most important point is Adapter, Before we go to ListView After adding data , We all call a method : notifyDataSetChanged(), This method uses what we call the observer model .

Follow up on this method notifyDataSetChanged Method , This method is defined in BaseAdapter in , The code is as follows :


public abstract class BaseAdapter implements ListAdapter, SpinnerAdapter {
    //  Data set observer 
    private final DataSetObservable mDataSetObservable = new DataSetObservable();

    //  Code ellipsis 

    public void registerDataSetObserver(DataSetObserver observer) {
        mDataSetObservable.registerObserver(observer);
    }

    public void unregisterDataSetObserver(DataSetObserver observer) {
        mDataSetObservable.unregisterObserver(observer);
    }

    /** * Notifies the attached observers that the underlying data has been changed * and any View reflecting the data set should refresh itself. *  Notify all observers when the data set changes  */
    public void notifyDataSetChanged() {
        mDataSetObservable.notifyChanged();
    }
}
 Copy code 

You can find , When the data changes ,notifyDataSetChanged Will call mDataSetObservable.notifyChanged() Method


public class DataSetObservable extends Observable<DataSetObserver> {
    /** * Invokes onChanged on each observer. Called when the data set being observed has * changed, and which when read contains the new state of the data. */
    public void notifyChanged() {
        synchronized(mObservers) {
            //  Call all the observers onChanged The way 
            for (int i = mObservers.size() - 1; i >= 0; i--) {
                mObservers.get(i).onChanged();
            }
        }
    }

}
 Copy code 

mDataSetObservable.notifyChanged() Traverse all observers in , And call their onChanged Method .

So where do these observers come from ? First ListView adopt setAdapter Method to set Adapter


 @Override
    public void setAdapter(ListAdapter adapter) {
        //  If there is already one adapter, Then log out of the Adapter The corresponding observer 
        if (mAdapter != null && mDataSetObserver != null) {
            mAdapter.unregisterDataSetObserver(mDataSetObserver);
        }

        //  Code ellipsis 

        super.setAdapter(adapter);

        if (mAdapter != null) {
            mAreAllItemsSelectable = mAdapter.areAllItemsEnabled();
            mOldItemCount = mItemCount;
            //  The amount of data obtained 
            mItemCount = mAdapter.getCount();
            checkFocus();
            //  Note that there  :  Create a dataset observer 
            mDataSetObserver = new AdapterDataSetObserver();
            //  Register this observer with Adapter in , Actually registered to DataSetObservable in 
            mAdapter.registerDataSetObserver(mDataSetObserver);

            //  Code ellipsis 
        } else {
            //  Code ellipsis 
        }

        requestLayout();
    }
 Copy code 

Set up Adapter It builds a AdapterDataSetObserver, Finally, register the observer to adapter in , So our observers 、 Observers have .

AdapterDataSetObserver It's defined in ListView Parent class of AbsListView in , The code is as follows :


 class AdapterDataSetObserver extends AdapterView<ListAdapter>.AdapterDataSetObserver {
        @Override
        public void onChanged() {
            super.onChanged();
            if (mFastScroll != null) {
                mFastScroll.onSectionsChanged();
            }
        }

        @Override
        public void onInvalidated() {
            super.onInvalidated();
            if (mFastScroll != null) {
                mFastScroll.onSectionsChanged();
            }
        }
    }
 Copy code 

It is inherited from AbsListView Parent class of AdapterView Of AdapterDataSetObserver, The code is as follows :


class AdapterDataSetObserver extends DataSetObserver {

        private Parcelable mInstanceState = null;
        //  call Adapter Of notifyDataSetChanged All observers will be called when onChanged Method , The core implementation is here 
        @Override
        public void onChanged() {
            mDataChanged = true;
            mOldItemCount = mItemCount;
            //  obtain Adapter Number of data in 
            mItemCount = getAdapter().getCount();

            // Detect the case where a cursor that was previously invalidated has
            // been repopulated with new data.
            if (AdapterView.this.getAdapter().hasStableIds() && mInstanceState != null
                    && mOldItemCount == 0 && mItemCount > 0) {
                AdapterView.this.onRestoreInstanceState(mInstanceState);
                mInstanceState = null;
            } else {
                rememberSyncState();
            }
            checkFocus();
            //  Rearrange ListView、GridView etc. AdapterView Components 
            requestLayout();
        }

        //  Code ellipsis 

        public void clearSavedState() {
            mInstanceState = null;
        }
    }
 Copy code 

When ListView When the data of , call Adapter Of notifyDataSetChanged function , This function will call DataSetObservable Of notifyChanged function , This function will call all observers (AdapterDataSetObserver) Of onChanged Method . This is the observer model !

summary :

AdapterView There is an inner class in AdapterDataSetObserver, stay ListView Set up Adapter It builds a AdapterDataSetObserver, And register to Adapter in , This is an observer . and Adapter Contains a data set that can be observed by DataSetObservable, When the amount of data changes, the developer manually calls AdapternotifyDataSetChanged, and notifyDataSetChanged It actually calls DataSetObservable Of notifyChanged function , This function will traverse all observers onChanged function . stay AdapterDataSetObserver Of onChanged Function gets Adapter New number of datasets in , And then call ListView Of requestLayout() Method to rearrange the layout , Update the user interface .

Well known open source frameworks that use the observer model include
EventBus
RxJava

5、 Pattern summary

5.1 advantage
  • The observer and the observed are abstractly coupled .
  • Set up a trigger mechanism .
5.2 shortcoming
  • If an observed object has many direct and indirect observers , It will take a lot of time to inform all the observers .
  • If there is a circular dependence between the observer and the observation target , Observing targets triggers a circular call between them , May cause system crash .
  • There is no corresponding mechanism for the observer model to let the observer know how the observed object changes , And just know that the observation target has changed .

copyright notice
author[Drizzle in winter],Please bring the original link to reprint, thank you.
https://en.cdmana.com/2022/01/202201281507184409.html

Random recommended