Android 最常用的设计模式二 安卓Rxjava源码分析—观察者模式Observer(有实例)
Android 最常用的设计模式一 安卓源码MediaManager分析—单例模式singleInstance
https://blog.csdn.net/WHB20081815/article/details/77970206
Android 最常用的设计模式二 安卓Rxjava源码分析—观察者模式Observer(有实例)
https://blog.csdn.net/WHB20081815/article/details/77970133
Android 最常用的设计模式三 安卓源码okhttp分析—— 代理模式(proxy)
https://blog.csdn.net/WHB20081815/article/details/77982008
Android 最常用的设计模式十一安卓源码分析——组合模式(component)
https://blog.csdn.net/WHB20081815/article/details/77980367
1.什么是观察者模式
2.优点是什么?怎么解耦
3.4个要素是什么?
4.应用场景 demo分析
5.android的场景
情景1
有一种短信服务,比如天气预报服务,一旦你订阅该服务,你只需按月付费,付完费后,每天一旦有天气信息更新,它就会及时向你发送最新的天气信息。
什么是观察者模式?一般提到原告,必然脑子立刻联想到被告,观察者和被观察者就如同原告和被告总是那么成对出现。观察者模式,又被叫做订阅模式,有订阅者和发布者。当下IPHONE6异常火爆,国内粉丝要想购买,那必须得预定,必须到它苹果官方去预定,填一大堆资料,交不交钱我不知道,反正得预定登记。等粉丝等到两眼欲穿、花儿快谢了时候,它粉墨登场了,官方以高姿态从容向预定过的粉丝发售。这苹果就是被观察者,粉丝就是观察者,观察者和被观察者之间需要建立联系,那就是登记。登记过后,被观察者拿捏火候觉得时机成熟的时候,就以权位者姿态向观察者抛出绣球,观察者迫不及待的伸出双手牢牢抓住后,满心欢喜的赞美苹果的伟大和自己的庆幸。睁大眼睛盯着目标看,期待期望结果,这就是观察者模式。
1.意图
定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。
主要解决:一个对象状态改变给其他对象通知的问题,而且要考虑到易用和低耦合,保证高度的协作。
/** * 我们来使用一下,我们定义了一个天气变换的主题,也就是被观察者,还有两个观察者观察天气变换,一旦变换了,就打印出天气信息, * 注意一定要调用被观察者的register进行注册,否则会收不到变换信息。 * 而一旦不敢兴趣了,直接调用unregister方法进行取消注册即可 */ public void ObserverTest(){//天气预报 Observable<Weather> observable=new Observable<Weather>(); Observer<Weather> observer1=new Observer<Weather>() {@Override public void onUpdate(Observable<Weather> observable, Weather data) {System.out.println("观察者1:"+data.toString()); }}; Observer<Weather> observer2=new Observer<Weather>() {@Override public void onUpdate(Observable<Weather> observable, Weather data) {System.out.println("观察者2:"+data.toString()); }}; //注册观察者 observable.register(observer1); observable.register(observer2); //天气发生了改变,通知观察者,注册了的观察者就能收到相应的信息 Weather weather=new Weather("晴转多云"); observable.notifyObservers(weather); Weather weather1=new Weather("多云转阴"); observable.notifyObservers(weather1); observable.unregister(observer1); Weather weather2=new Weather("台风"); observable.notifyObservers(weather2); }
/** * Created by Administrator on 2017/9/13. * 封装业务,观察者和被观察者的业务封装 * 观察者:注册监听,谁注册谁能收到 * 被观察者:有信息变化的时候通知观察者 * */ public class Observable <T>{List<Observer<T>> mObservers = new ArrayList<Observer<T>>(); //注册 public void register(Observer<T> observer) {if (observer == null) {throw new NullPointerException("observer == null"); }synchronized (this) {if (!mObservers.contains(observer))mObservers.add(observer); }}/**反注册*/ public synchronized void unregister(Observer<T> observer) {mObservers.remove(observer); }public void notifyObservers(T data) {for (Observer<T> observer : mObservers) {observer.onUpdate(this, data); }}}
/** * Created by Administrator on 2017/9/13. * 观察者得到的更新接口 */ public interface Observer <T> {void onUpdate(Observable<T> observable,T data); }
public class Weather {public Weather(String description){this.description=description; }private String description; public String getDescription() {return description; }public void setDescription(String description) {this.description = description; }}
这套系统中主要包括三个部分:气象站(获取天气数据的物理设备)、WeatherData(追踪来自气象站的数据,并更新公告牌)、公告牌(用于展示天气数据)
错误示范
我们现来看看隔壁老王的实现思路:
public class WeatherData {//实例变量声明...public void measurementsChanged() {float temperature = getTemperature();float humidity = getHumidity();float pressure = getPressure();List<Float> forecastTemperatures = getForecastTemperatures();//更新公告牌currentConditionsDisplay.update(temperature, humidity, pressure);forecastDisplay.update(forecastTemperatures);}...
}复制代码
上面这段代码是典型的针对实现编程,这会导致我们以后增加或删除公告牌时必须修改程序。我们现在来看看观察者模式,然后再回来看看如何将观察者模式应用到这个程序。
主题接口
/*** 主题(发布者、被观察者) 被观察者一般保函3个:注册,移除和通知(和点击事件一样)*/
public interface Subject {/*** 注册观察者*/void registerObserver(Observer observer);/*** 移除观察者*/void removeObserver(Observer observer);/*** 通知观察者*/void notifyObservers();
}
观察者接口
/**
* 观察者(用于更新的一个接口方法)*/
public interface Observer {void update();
}复制代码
公告牌用于显示的公共接口
public interface DisplayElement {void display();
}
中间类:
下面我们再来看看WeatherData是如何实现的:被观察者的生命周期
public class WeatherData implements Subject {private List<Observer> observers;private float temperature;//温度private float humidity;//湿度private float pressure;//气压private List<Float> forecastTemperatures;//未来几天的温度public WeatherData() {this.observers = new ArrayList<Observer>();}@Overridepublic void registerObserver(Observer observer) {this.observers.add(observer);}@Overridepublic void removeObserver(Observer observer) {this.observers.remove(observer);}@Overridepublic void notifyObservers() {for (Observer observer : observers) {observer.update();}}public void measurementsChanged() {notifyObservers();}public void setMeasurements(float temperature, float humidity, float pressure, List<Float> forecastTemperatures) {this.temperature = temperature;this.humidity = humidity;this.pressure = pressure;this.forecastTemperatures = forecastTemperatures;measurementsChanged();}public float getTemperature() {return temperature;}public float getHumidity() {return humidity;}public float getPressure() {return pressure;}public List<Float> getForecastTemperatures() {return forecastTemperatures;}
}
显示当前天气的公告牌CurrentConditionsDisplay:观察者的更新方法和ui的显示方法
public class CurrentConditionsDisplay implements Observer, DisplayElement {private WeatherData weatherData;private float temperature;//温度private float humidity;//湿度private float pressure;//气压public CurrentConditionsDisplay(WeatherData weatherData) {this.weatherData = weatherData;this.weatherData.registerObserver(this);}@Overridepublic void display() {System.out.println("当前温度为:" + this.temperature + "℃");System.out.println("当前湿度为:" + this.humidity);System.out.println("当前气压为:" + this.pressure);}@Overridepublic void update() {this.temperature = this.weatherData.getTemperature();this.humidity = this.weatherData.getHumidity();this.pressure = this.weatherData.getPressure();display();}
}
好处:后面如果我们需要增加或者删除公告牌就只需要新增或者删除实现了
Observer和DisplayElement
接口的公告牌就好了。
总结:
观察者模式的结构中包含四种角色:
(1)主题(Subject):主题是一个接口,该接口规定了具体主题需要实现的方法,比如,添加、删除观察者以及通知观察者更新数据的方法。
(2)观察者(Observer):观察者是一个接口,该接口规定了具体观察者用来更新数据的方法。
(3)具体主题(ConcreteSubject):具体主题是实现主题接口类的一个实例,该实例包含有可以经常发生变化的数据。具体主题需使用一个集合,比如ArrayList,存放观察者的引用,以便数据变化时通知具体观察者。
(4)具体观察者(ConcreteObserver):具体观察者是实现观察者接口类的一个实例。具体观察者包含有可以存放具体主题引用的主题接口变量,以便具体观察者让具体主题将自己的引用添加到具体主题的集合中,使自己成为它的观察者,或让这个具体主题将自己从具体主题的集合中删除,使自己不再是它的观察者。
来源: https://www.cnblogs.com/xuwendong/p/9814417.html
1.观察者(封装更新方法)
2.被观察者———转接桥梁(封装了注册和更新的方法)
3.事件(实体信息,内容)
4.观察者模式的三个典型方法它都具有,即注册,取消注册,发送事件
5.传输数据,有注册信息相关的组件就用到了观察者模式
实现观察者模式有很多形式,一种是“注册---通知---撤销注册”的形式。
观察者模式的应用场景:
- 当一个对象的改变需要通知其它对象改变时,而且它不知道具体有多少个对象有待改变时。
- 当一个对象必须通知其它对象,而它又不能假定其它对象是谁
- 跨系统的消息交换场景,如消息队列、事件总线的处理机制。
1、 对一个对象状态的更新,需要其他对象同步更新,而且其他对象的数量动态可变。
2、 对象仅需要将自己的更新通知给其他对象而不需要知道其他对象的细节。
安卓中用到的观察者模式
1.观察者模式:
电视前的你也就是观察者可以看,(对象发生变化)电视里被观察者做了别的动作,那么电视前的所有人看到的也就变了,在同一时间改变所有观众看到的画面。
比如说BaseAdapter AbsListView
RecyclerView
我们可以通过BaseAdapter.registerDataSetObserver和BaseAdapter.unregisterDataSetObserver两方法来向BaseAdater注册、注销一个DataSetObserver。这个过程中,DataSetObserver就是一个观察者,它一旦发现BaseAdapter内部数据有变量,就会通过回调方法DataSetObserver.onChanged和DataSetObserver.onInvalidated来通知DataSetObserver的实现类。事件通知也是观察者模式
简介:一个对象发生改变时,所有信赖于它的对象自动做相应改变。
<span style="color:gray"><span style="color:#abb2bf"><code><span style="color:#c678dd">public</span> <span style="color:#c678dd">abstract</span> <span style="color:#c678dd">class</span> <span style="color:#e6c07b">BaseAdapter</span> <span style="color:#c678dd">implements</span> <span style="color:#e6c07b">ListAdapter</span>, <span style="color:#e6c07b">SpinnerAdapter</span> {<span style="color:#929292">//数据集被观察者</span><span style="color:#c678dd">private</span> <span style="color:#c678dd">final</span> DataSetObservable mDataSetObservable = <span style="color:#c678dd">new</span> DataSetObservable();<span style="color:#929292">//注册观察者</span><span style="color:#c678dd">public</span> <span style="color:#c678dd">void</span> <span style="color:#61aeee">registerDataSetObserver</span>(DataSetObserver observer) {mDataSetObservable.registerObserver(observer);}<span style="color:#929292">//注销观察者</span><span style="color:#c678dd">public</span> <span style="color:#c678dd">void</span> <span style="color:#61aeee">unregisterDataSetObserver</span>(DataSetObserver observer) {mDataSetObservable.unregisterObserver(observer);}<span style="color:#929292">//数据集改变时,通知所有观察者</span><span style="color:#c678dd">public</span> <span style="color:#c678dd">void</span> <span style="color:#61aeee">notifyDataSetChanged</span>() {mDataSetObservable.notifyChanged();}
}<span style="color:#929292">//其他代码略</span></code>
</span></span>
来源: https://www.jianshu.com/p/8f32da74cd8b
2.Android的广播机制LocalBroadcastManager
我们平时使用本地广播主要就是下面四个方法
LocalBroadcastManager localBroadcastManager=LocalBroadcastManager.getInstance(this); localBroadcastManager.registerReceiver(BroadcastReceiver receiver, IntentFilter filter); localBroadcastManager.unregisterReceiver(BroadcastReceiver receiver); localBroadcastManager.sendBroadcast(Intent intent)
3.EventBus
观察者模式的三个典型方法它都具有,即注册,取消注册,发送事件
EventBus.getDefault().register(Object subscriber); EventBus.getDefault().unregister(Object subscriber); EventBus.getDefault().post(Object event);
http://www.cnblogs.com/shijiacheng/p/5059067.html
4.RecyclerView中的addOnScrollListener方法
观察者模式的优点:
1、 Subject和Observer之间是松偶合的,分别可以各自独立改变。
2、 Subject在发送广播通知的时候,无须指定具体的Observer,Observer可以自己决定是否要订阅Subject的通知。
3、 遵守大部分GRASP原则和常用设计原则,高内聚、低偶合。
5.。RxJava
自己在项目中的运用如下:
GPS位置信息监听
上面对按钮监听是属于一对一的观察者模式,当然你也可以用一个Listener监听多个按钮。下面我们再讲一个标准的一对多的观察者模式的应用。在我们使用GPS模块的时候,需要监听GPS模块位置变化,通常我们会编写下面代码:
//Edited by mythou //http://www.cnblogs.com/mythou/
// 通过GPS定位 String LocateType= locationManager.GPS_PROVIDER; Location location = locationManager.getLastKnownLocation(LocateType); // 设置监听器,设置自动更新间隔这里设置1000ms,移动距离:0米。 locationManager.requestLocationUpdates(provider, 1000, 0, locationListener); // 设置状态监听回调函数。statusListener是监听的回调函数。locationManager.addGpsStatusListener(statusListener); //监听器实现private final GpsStatus.Listener statusListener = new GpsStatus.Listener() {public void onGpsStatusChanged(int event) {// GPS状态变化时的回调,获取当前状态GpsStatus status = locationManager.getGpsStatus(null); //自己编写的方法,获取卫星状态相关数据GetGPSStatus(event, status);} };
GPS位置服务是Framework的一个系统层服务,整个系统只有一个运行的实例。但实际使用时,可能会出现好几个应用都在使用这个服务,因此会形成了一个一对多的观察者例子。这里不对代码进行深入对比讲解,只要对照上面的讲解,你就可以把目标对象、观察者接口、观察者实现、数据更新回调接口找出来。有兴趣的朋友还可以追查Android的源码,看看GpsStatus里面的具体实现。
观察者模式在实际项目的应用中非常常见,比如你到 ATM 机器上取钱,多次输错密码,卡就会被 ATM吞掉,吞卡动作发生的时候,会触发哪些事件呢?第一摄像头连续快拍,第二,通知监控系统,吞卡发生;第三,初始化 ATM 机屏幕,返回最初状态,你不能因为就吞了一张卡,整个 ATM 都不能用了吧,一般前两个动作都是通过观察者模式来完成的。观察者可以实现消息的广播,一个消息可以触发多个事件,这是观察者模式非常重要的功能。
继续以送快递为例,快递员有时只是把快递拉到楼下,然后就通知收件人下楼去取快递。
优点:(解耦,方便以后添加方法扩展)
1、具体主题和具体观察者是松耦合关系。由于主题接口仅仅依赖于观察者接口,因此具体主题只是知道它的观察者是实现观察者接口的某个类的实例,但不需要知道具体是哪个类。同样,由于观察者仅仅依赖于主题接口,因此具体观察者只是知道它依赖的主题是实现主题接口的某个类的实例,但不需要知道具体是哪个类。
关于观察者的一切,主题只知道观察者实现了Observer接口,并不需要观察者具体的类是谁,做了什么或者其他细节
- 解除观察者与主题之间的耦合。让耦合的双方都依赖于抽象,而不是依赖具体。从而使得各自的变化都不会影响另一边的变化。
- 易于扩展,对同一主题新增观察者时无需修改原有代码。
2、观察者模式满足“开-闭原则”。主题接口仅仅依赖于观察者接口,这样,就可以让创建具体主题的类也仅仅是依赖于观察者接口,因此,如果增加新的实现观察者接口的类,不必修改创建具体主题的类的代码。。同样,创建具体观察者的类仅仅依赖于主题接口,如果增加新的实现主题接口的类,也不必修改创建具体观察者类的代码。
缺点:
1、如果一个被观察者对象有很多的直接和间接的观察者的话,将所有的观察者都通知到会花费很多时间。(遍历太多了,可能会引起多余的数据通知。)
2、如果在观察者和观察目标之间有循环依赖的话,观察目标会触发它们之间进行循环调用,可能导致系统崩溃。(死循环)
3、观察者模式没有相应的机制让观察者知道所观察的目标对象是怎么发生变化的,而仅仅只是知道观察目标发生了变化。
参考博客:
https://juejin.im/post/57de12355bbb50005e648bd8
Android 最常用的设计模式二 安卓Rxjava源码分析—观察者模式Observer(有实例)相关推荐
- Rxjava源码分析之IO.Reactivex.Observable
Rxjava 源码系列目录 Rxjava源码分析之IO.Reactivex.Observer Rxjava源码分析之IO.Reactivex.CompositeDisposable Rxjava源码分 ...
- 10章 RxJava源码分析
本篇文章已授权微信公众号 YYGeeker 独家发布转载请标明出处 CSDN学院课程地址 RxJava2从入门到精通-初级篇:https://edu.csdn.net/course/detail/10 ...
- Rxjava源码分析之IO.Reactivex.CompositeDisposable
Rxjava 源码系列目录 Rxjava源码分析之IO.Reactivex.Observer Rxjava源码分析之IO.Reactivex.CompositeDisposable Rxjava源码分 ...
- Rxjava源码分析之IO.Reactivex.Observer
Android 中的观察者模式,Rxjava中有两个重要的类Observable和Observer,函数响应式编程具体表现为一个观察者(Observer)订阅一个可观察对象(Observable).通 ...
- Android Retrofit 2.0(三)从源码分析原理
Retrofit·特点 性能最好,处理最快 使用REST API时非常方便: 传输层默认就使用OkHttp: 支持NIO: 拥有出色的API文档和社区支持 速度上比volley更快: 如果你的应用程序 ...
- 【朝花夕拾】Android自定义View篇之(六)Android事件分发机制(中)从源码分析事件分发机制...
前言 转载请注明,转自[https://www.cnblogs.com/andy-songwei/p/11039252.html]谢谢! 在上一篇文章[[朝花夕拾]Android自定义View篇之(五 ...
- 【朝花夕拾】Android自定义View篇之(六)Android事件分发机制(中)从源码分析事件分发逻辑及经常遇到的一些“诡异”现象
前言 转载请注明,转自[https://www.cnblogs.com/andy-songwei/p/11039252.html]谢谢! 在上一篇文章[[朝花夕拾]Android自定义View篇之(五 ...
- C#调用obs studio 二次开发 源码分析 编译
C#二次开发obs studio obs studio二次开发视频教程,录制.推流.调整分辨率.调整位置.画面回调.推流回调等功能 obs二次开发还是比较繁琐的,我在学习的时候也是很痛苦,有需要的朋友 ...
- Java设计模式学习以及底层源码分析
源码在分支master 工厂模式 把具体创建产品的细节封装起来,你要什么产品,我给你什么产品即可. 简单工厂模式 工厂方法模式 缓存层:抽象类 抽象工厂模式 缓存层是:接口 原型模式 问题: 原型模式 ...
- 【深入设计模式】单例模式—从源码分析内部类单例、枚举单例以及单例模式在框架中的应用
文章目录 1. 使用静态内部类实现单例模式 1.1 静态内部类单例写法 1.2 如何实现懒加载 1.3 为什么线程安全 2. 枚举类型单例单例模式 2.1 枚举类型单例写法 2.2 枚举类型单例原理 ...
最新文章
- 部署ArcGIS JS API 离线包(Tomcat与IIS)
- window系统安装redis步骤
- 登录界面点击登录后如何延迟提示成功的div的显示时间并跳转
- 14怎么敷铜不了_YEO护肤课堂:敷面膜有什么误区?我们应该如何选择面膜?
- 在内存中创建临时表和表变量
- Ngnix中的fastcgi參数性能优化和解释
- 计算时间:一个C++运算符重载示例
- mysql漏洞如何打补丁_WordPress 5.1 CSRF to RCE 漏洞详解
- Linux使用命令刻录镜像到U盘
- 在线log计算机,log换算(log计算器在线)
- 物联网应用案例:镇海智慧水务
- Office从2019版本降至2016版本
- 全球及中国抗体药物市场展望规划及专项深度调研报告2021-2027年
- 水逆了一整年的王源,2020年年初能靠《大主宰》翻身吗?
- 投稿指南【NO.7】目标检测论文写作模板(初稿)
- 空洞卷积/扩张卷积(Dilated convolution)-笔记
- Python学习笔记(八)—切片(slicing)
- LaTeX Error: File `numcompress.sty‘ not found. 解决方案
- 培养数字化人才 护航大学生就业 千锋教研院2022年教研战略发布会隆重举行
- Android Hawk数据库 github开源项目,字节跳动社招面试记录
热门文章
- 使用R语言进行单(双)因素方差分析
- 图的拓补排序(TopologicalSort)算法在邻接表与邻接矩阵结构下实现
- uniapp app 腾讯云 IM 创建群组(陌生交友)
- 秒懂设计模式之桥接模式(Bridge Pattern)
- 如何区分手机端 APP 是原生 APP 还是 H5?H5 和原生 APP 之间的区别
- html背景左右渐变,css 背景 上下渐变 左右渐变
- AE无法输出h.264 安装Quick time也不好使的办法 本人使用 AE CC2019
- 【6】python生成数据曲线平滑处理——(Savitzky-Golay 滤波器、convolve滑动平均滤波)方法介绍,推荐玩强化学习的小伙伴收藏
- java excel下拉框_Java设置Excel下拉列表
- 爬虫爬取taptap上关于厂商的评论