The observer mode, composed of the observer and the observed object,Java has provided related classes for our developers to call! Observables monitor network changes in many situations during app development, such as Socket long links, video online playback, wake up certain services, friendly user experience considerations…

In this scenario, an Observable is a network state and an Observer is an Activity

Observable Maintains a collection of observers, List observers = new ArrayList(); Observable is used to notify a group of Observer objects when a change * occurs. On creation, the set of observers is empty. After a change occurred, * the application can call the {@link #notifyObservers()} method. This will * cause the invocation of the {@code update()} method of all registered * Observers. The order of invocation is not specified. This implementation will * call the Observers in the order they registered. Subclasses are completely * free in what order they call the update methods. * * @see Observer */

An Observable notifies all observers in the collection when data changes! After data changes, the app calls notifyObservers, and updates () for every Observer in the collection are executed.

Observable< Observable object >

 public class NetObservable extends Observable {
    private Context context;

    public NetObservable(Context context) {
        super(a);this.context = context;
    }

    @Override
    public void addObserver(Observer observer) {
        try {
            super.addObserver(observer);
            NetworkInfo networkInfo = Network.getCurrentActiveNetwork(this.context);// Get the network available for the current connection
            if(networkInfo ! =null) {
                if(! networkInfo.isAvailable()) {// The network is unavailable
                    observer.update(this.new NetObserver.NetAction(false.false, Network.getSubType(context)));
                    return;
                }

                if (networkInfo.getType() == ConnectivityManager.TYPE_WIFI) {//WIFI
                    observer.update(this.new NetObserver.NetAction(true.true, Network.getSubType(context)));
                    return;
                }
                / / not WIFI
                observer.update(this.new NetObserver.NetAction(true.false, Network.getSubType(context)));
                return;
            }
            / / there is no network
            observer.update(this.new NetObserver.NetAction(false.false, Network.getSubType(context)));
        } catch(Exception e) { e.printStackTrace(); }}@Override
    public void notifyObservers(Object data) {
        try {
            this.setChanged();// Set an internal flag indicating that the data has changed
            super.notifyObservers(data);
        } catch(Exception e) { e.printStackTrace(); }}}Copy the code

AddObserver (Observer Observer) : addObserver(Observer Observer) : addObserver(Observer Observer) :

    public void addObserver(Observer observer) {
        if (observer == null) {
            throw new NullPointerException("observer == null");
        }
        synchronized (this) {
            if (!observers.contains(observer))
                observers.add(observer);
        }
    }Copy the code

Very simple, the parent method, is to join the inner collection without repeating! NetObservable overwrites the addObserver method just to give the observer immediate feedback on the current network state when first added! NotifyObservers is also overwritten by calling this.setchanged () first; Then call super.notifyObservers(data); SetChanged () is the key here, she sets the internal flag to true changed = true, and here is the notification parent method

 public void notifyObservers(Object data) {
        int size = 0;
        Observer[] arrays = null;
        synchronized (this) {
            if (hasChanged()) {// If changed==true, populate the Arrays array
                clearChanged();
                size = observers.size();
                arrays = newObserver[size]; observers.toArray(arrays); }}if(arrays ! =null) {// All objects of the array class are notified if they have been populated
            for (Observer observer : arrays) {
                observer.update(this, data); }}}Copy the code

Observer = Observer = Observer

public abstract class NetObserver implements Observer {
    public static class NetAction {
        private boolean isAvailable;
        private boolean isWifi;
        private Network.Type type;

        public NetAction(boolean isAvailable, boolean isWifi, Network.Type type) {
            super(a);this.isAvailable = isAvailable;
            this.isWifi = isWifi;
            this.type = type;
        }

        public boolean isAvailable() {
            return this.isAvailable;
        }

        public Network.Type getType() {
            return type;
        }

        public void setType(Network.Type type) {
            this.type = type;
        }

        public boolean isWifi() {
            return this.isWifi; }}public abstract void notify(NetAction action);

    @Override
    public void update(Observable observable, Object data) {
        this.notify(((NetAction) data)); }}Copy the code

Analysis: There’s an abstract method called notify, where the observer only cares about results like NetAction, not Observable, so subclasses can override that abstract method if you want to get Observable, override the update method!

Step 3: When to notify the observer of a change in network status, of course, look at the receiver

 public class NetMonitor extends BroadcastReceiver {
    private static final String TAG = "NetMonitor";
    private static NetMonitor instance;
    private NetObservable observable;


    public void addObserver(NetObserver observer) {// Add an observer
        this.observable.addObserver(observer);
    }

    public void delObserver(NetObserver observer) {// Delete an observer
        this.observable.deleteObserver(observer);
    }

    public void destory() {// Destroy method, delete all observers
        this.observable.deleteObservers();
        this.observable = null;
    }

    public static NetMonitor getInstance() {// Singleton mode
        if (instance == null) {
            synchronized (NetMonitor.class) {
                if (instance == null) {
                    instance = newNetMonitor(); }}}return instance;
    }

    public void init(Context context) {// Initialize, preferably in Application, only once
        this.observable = new NetObservable(context);
        IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction("android.net.conn.CONNECTIVITY_CHANGE");
        context.registerReceiver(this, intentFilter);//Context registers broadcast
    }

    // The data source has changed, telling the observed NetObservable(unique)
    private void notifyNetState(Context context) {
        try {
            NetworkInfo networkInfo = Network.getCurrentActiveNetwork(context);
            if(networkInfo ! =null) {
                if(! networkInfo.isAvailable()) {this.observable.notifyObservers(new NetObserver.NetAction(false.false, Network.getSubType(context)));
                    return;
                }
                if (networkInfo.getType() == ConnectivityManager.TYPE_WIFI) {
                    this.observable.notifyObservers(new NetObserver.NetAction(true.true, Network.getSubType(context)));
                    return;
                }

                this.observable.notifyObservers(new NetObserver.NetAction(true.false, Network.getSubType(context)));
                return;
            }

            this.observable.notifyObservers(new NetObserver.NetAction(false.false, Network.getSubType(context)));
        } catch(Exception e) { e.printStackTrace(); }}@Override
    public void onReceive(Context context, Intent intent) {
        this.notifyNetState(context); }}Copy the code

Analysis: in the application startup time, first take a singleton initialization, ha ha, routine! Yes, the source is NetMonitor, think of active MVC, where NetMonitor acts as the Controller Controller,NetObservable is a Model, and NetObserver is a View, and the events passed in between are NetActions! NetMonitor tells the model layer NetObservable that your NetAction event is coming, so notify the View layer immediately and complete the event delivery.

Finally, look at the top layer:

  private NetObserver mNetObserver = new NetObserver() {/ / observer
        @Override
        public void notify(NetAction action) {
            if (action.isAvailable()) {
                Log.e(MainActivity.class.getSimpleName(), "Network Availability >" + "Network type :" + action.getType().toString());
            } else {
                Log.e(MainActivity.class.getSimpleName(), "Network unavailable >" + "Network type :"+ action.getType().toString()); }}};@Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        NetMonitor.getInstance().addObserver(this.mNetObserver);/ / register
    }


    @Override
    protected void onDestroy() {
        super.onDestroy();
        NetMonitor.getInstance().delObserver(this.mNetObserver);// Cancel registration
    }
Copy the code

Finally, NetAction has an enumerated class member, net. Type, that describes the Network Type in detail:

  public enum Type {
        UNKNOWN, WIFI, MOBILE, MOBILE2G, MOBILE3G, MOBILE4G
  }Copy the code

PS: When making an App, in order to save traffic for users, not to provoke users’ anger, and for better user experience, some adjustments need to be made according to users’ current network conditions. Users can also choose by themselves in the App setting module under 2G / 3G / 4G network conditions. Whether to allow requests for some heavy traffic data.

So how do you tell the difference? NETWORK_TYPE_GPRS/NETWORK_TYPE_LTE… .). In fact, how to judge the user 2G/3G/4G mobile data network, source TelephonyManager has a method getNetworkClass can meet, but the tragedy is hidden by the system, hit the @hide tag, but Consider reflection calls! The code for API 23 is as follows:

   /**
     * Return general class of network type, such as "3G" or "4G". In cases
     * where classification is contentious, this method is conservative.
     *
     * @hide* /
    public static int getNetworkClass(int networkType) {
        switch (networkType) {
            case NETWORK_TYPE_GPRS:
            case NETWORK_TYPE_GSM:
            case NETWORK_TYPE_EDGE:
            case NETWORK_TYPE_CDMA:
            case NETWORK_TYPE_1xRTT:
            case NETWORK_TYPE_IDEN:
                return NETWORK_CLASS_2_G;
            case NETWORK_TYPE_UMTS:
            case NETWORK_TYPE_EVDO_0:
            case NETWORK_TYPE_EVDO_A:
            case NETWORK_TYPE_HSDPA:
            case NETWORK_TYPE_HSUPA:
            case NETWORK_TYPE_HSPA:
            case NETWORK_TYPE_EVDO_B:
            case NETWORK_TYPE_EHRPD:
            case NETWORK_TYPE_HSPAP:
            case NETWORK_TYPE_TD_SCDMA:
                return NETWORK_CLASS_3_G;
            case NETWORK_TYPE_LTE:
            case NETWORK_TYPE_IWLAN:
                return NETWORK_CLASS_4_G;
            default:
                returnNETWORK_CLASS_UNKNOWN; }}Copy the code

To this, the whole registration, notification process is finished analysis, it is best to personally print the network status change, especially from WIFI switch to mobile network, or from mobile network switch to WIFI, see the broadcast situation, thank you for browsing. ~~~

Project delivery: github.com/shonegg/Net…