在Android中,或者说Java中,监听模式都是非常常见的。当你激发某个事件,常常你需要等待这个事件的返回。
如果这个事件是个异步事件,那么监听总是显得很有必要。
举个日常的例子,当你在android中连接网络并发送请求时,你就常常需要用到异步监听,用于监听并回调请求结果。这个就是异步回调。
观察者模式与回调模式有很多的相似处,简单对比就是:回调是一对一的关系,只监听一个事件;观察者模式则是一个主题,可以有多个监听,当主题变化时,向所有(也可以试部分)这些监听发出变化通知,观察者模式是一对多的关系。
回调模式:
那么我们就从简单的聊起吧,作为一名android开发者,我相信都用过回调,但是我们在用的过程中不知道那就是回调而已。举个简单的例子来说吧,我们学生在考试时,拿到卷子的第一件事是什么?就是填写自己的学号和姓名,这样老师在改卷的过程中,才知道这是哪名学生。这就是回调,我们填写学号和姓名不是给自己看的(即该方法不是给自己用的),是给老师批卷时用的(给系统预留将来调用的),老师给我们在卷子上提供填写学号姓名的文本框(即系统提供接口),我们填写(即利用接口注册)。
在android中,我们用到的回调实在是太多了,最简单的一个,按钮的点击事件;
- Button button = (Button)this.findViewById(R.id.button);
- button.setOnClickListener(newButton.OnClickListener() {
- //回调函数
- @override
- publicvoidonClick(View v) {
- buttonTextView.setText("按钮被点击了");
- }
- });
这么写点击事件,你写过onClick()方法么?没有吧,这是系统自己提供的一个方法,我们不会自己去显示的调用onClick()方法,只有在用户触发了点击事件,android系统就会自己去调用onClick()方法,我们只需要写,当用户触发之后我们该做什么就可以了。
我们知道java中是没有指针这概念的,但是并不代表java中没有指针,java用引用代替指针,其实回调函数本质上就是一个通过函数指针来调用的一个函数,如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用为调用它所指向的函数时,我们就说这是回调函数。回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应。
Java 中没有指针的概念,通过接口和内部类的方式实现回调的功能:
1.定义一个接口
2.定义接口中未实现业务逻辑的方法
3.传递一个实现了此接口类的对象
4.获取传递进来的对象,在合适的地方,做方法的调用
这里举一个简单的例子来演示一下怎么完成这4步:
比如说,现在要实现一个显示下载进度的效果,我们可以用ProgressBar来动态显示,当然也可以用TextView将下载进度显示出来,但是两个不能同时显示,这时,我们最好就是写一个方法,让我想显示ProgressBar就显示ProgressBar,想用TextView时,就用TextView。
先定义public interface CallBack{}接口再说,现在再想,接口里要写什么方法呢?这时我们就要想,调用这个接口的方法需要什么,不管是ProgressBar还是TextView,我们都需要给它设置大小和进度吧,那么我们就需要两个方法
public interface CallBack{
void setMax(int max);
void setProgress(int index);
}
这样1,2步就完成了,然后再在方法中调用
public void A(int max,int index,CallBack callback){
callback.setMax(max);
callback setProgress(index);
}
当某个类中需要调用此方法时,则需要实现接口中未实现的方法
a.A(max,index,new CallBack{
public void setMax(int max){
//这里就可以实现效果,如果想用ProgressBar,就用ProgressBar的对象来调用这个方法
pb.setMax(max);
//如果想用TextView就用TextView对象调用
tv.setMax(max);
}
public void setProgress(int index){
//同理
}
});
这样你就成功使用了回调来解决了问题;
观察者模式:
简单的说就是:一个主题,该主题自带被订阅、被取消订阅、通知这三个功能。而这个主题可以被多个观察者订阅,从而形成一对多的关系。
根据这描述我们先写下主题和观察者的接口(一般写为接口或者抽象类)。
这里也举个简单的例子来比较记忆:每天的天气预报,我们可以这样来分解,天气预报是一个被观察者,观看的人就是观察者,天气预报要提供哪些功能呢,第一,它需要提供可以被观众收到的方法,也就是我们常说的注册方法,第二,还得提供观众不看了的方法,也就是注销方法,第三,作为天气预报,你有责任通知观众未来几天的天气变化,也就是通知方法。而观众要什么呢?观众既然收看了天气预报,那么就得去筹划未来几天该做什么事,下雨了明天就不能出去了,晴天就可以出去打球类似这些事,那么观察者就需要一个接口,要做的事就是要接口里的方法;那么我们就可以这样实现
1.被观察者的接口
- public interface Subject {
- public void addObserver(Observer observer);
- public void removeObserver(Observer observer);
- public void notifyObservers();
- }
2.观察者的接口
- public interface Observer {
- public void doSomething(String msg);
- }
3.被观察者实现接口的方法
- public class SubjectImp implements Subject{
- private List<Observer> list=new ArrayList<Observer>();
- private String msg;
- @Override
- public void addObserver(Observer observer) {
- // TODO Auto-generated method stub
- list.add(observer);
- }
- @Override
- public void removeObserver(Observer observer) {
- // TODO Auto-generated method stub
- int index=list.indexOf(observer);
- if(index>=0){
- list.remove(index);
- }
- }
- @Override
- public void notifyObservers() {
- // TODO Auto-generated method stub
- for(Observer observer:list){
- observer.dosomething(msg);
- }
- }
- public void setMsg(String msg){
- this.msg=msg;
- notifyObservers();
- }
- }
4.观察者1实现接口方法
- public class ObserverImp implements Observer{
- Subject subject;
- public ObserverImp(Subject subject){
- this.subject=subject;
- subject.addObserver(this);
- }
- @Override
- public void dosomething(String msg) {
- // TODO Auto-generated method stub
- System.out.println("收到:"+msg);
- }
- }
5.观察者2实现接口方法
- public class ObserverImp1 implements Observer{
- Subject subject;
- public ObserverImp1(Subject subject){
- this.subject=subject;
- subject.addObserver(this);
- }
- @Override
- public void update(String msg) {
- // TODO Auto-generated method stub
- System.out.println("收到:"+msg);
- }
- }
- SubjectImp subjectImp=new SubjectImp();
- ObserverImp observerImp=new ObserverImp(subjectImp);
- ObserverImp1 observerImp1=new ObserverImp1(subjectImp);
- subjectImp.setMsg("ok");
这就是简单的一个观察者模式;