1.监听器Listener
Android中监听器非常常见,下面我们来看一下最典型的button绑定监听器的例子:
public class MainActivity extends AppCompatActivity implements View.OnClickListener{//观察者(接口),回调接口
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button button=findViewById(R.id.button1);
button.setOnClickListener(this);//注册观察者
}
@Override
public void onClick(View v) {//回调函数
//响应点击
}
}
View源码:
public class View implements Drawable.Callback, KeyEvent.Callback, AccessibilityEventSource {//主题(接口)
protected OnClickListener mOnClickListener;
public void setOnClickListener(OnClickListener l) {
if (!isClickable()) {
setClickable(true);
}
mOnClickListener = l;
}
public boolean performClick() {
sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);
if (mOnClickListener != null) {
playSoundEffect(SoundEffectConstants.CLICK);
mOnClickListener.onClick(this);
return true;
}
return false;
}
}
首先说明,onClick是回调函数,OnClickListener是回调接口;这里你可能不明白为什么,下面一节我将引入一个生动的例子来讲解回调机制。
2.回调
查询相关资料后,有人说回调是:在A类中调用B类的方法C,在B类中调用A的方法D,D就是回调方法。
回调机制的要求:
- A类实现了CallBack接口;
- A类中包含B的引用;
- A类中调用B类的方法C;
- 在B类中调用A的方法D
现有如下需求**:现在有两家手机公司OPPO和VIVO要找代理生产商富士康(Foxconn)代理生产他们的新手机。OPPO和VIVO会分别让技术人员和采办人员携带手机设计方案和原材料去富士康监督生产。手机生产结束后,Foxconn会分别通过邮件和微信的方式通知OV它们手机的良品率。
手机厂商接口:
public interface CellPhoneCompany {//手机厂商,回调接口,观察者接口
public void getNotification(double yield);//回调方法,生产结束后通知良品率
}
代工厂富士康:
public class Foxconn {//主题,最好让其继承一个主题接口
private double yield;
/**
*@params: [material, design, cellPhoneCompany] =
*[原材料,设计方案,手机厂商]
*@Descrption:
*/
public void produceCellPhone(int material,int design,CellPhoneCompany cellPhoneCompany){
yield=getYield(material,design);//主题状态发生变化
cellPhoneCompany.getNotification(yield);//通知观察者
}
}
Oppo:
public class OPPO implements CellPhoneCompany {//观察者
private String email;
private String WeChat;
private int material;
private int design;
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getWeChat() {
return WeChat;
}
public void setWeChat(String weChat) {
WeChat = weChat;
}
public int getMaterial() {
return material;
}
public void setMaterial(int material) {
this.material = material;
}
public int getDesign() {
return design;
}
public void setDesign(int design) {
this.design = design;
}
/**
* 获取富士康的良品率通知
* @param yield 良品率
*/
@Override
public void getNotification(double yield) {
notifyByEmail(email,yield);
}
/**
*@params: [material, design]OppoFindx的原材料和设计方案
*@Descrption: 找代工厂生产OppoFindx
*/
public void produceOppoFindx(int material,int design){
new Foxconn().produceCellPhone(material,design,this);
}
}
Vivo:
public class Vivo implements CellPhoneCompany {//观察者
private String email;
private String weChat;
private int material;
private int design;
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getWeChat() {
return weChat;
}
public void setWeChat(String weChat) {
this.weChat = weChat;
}
public int getMaterial() {
return material;
}
public void setMaterial(int material) {
this.material = material;
}
public int getDesign() {
return design;
}
public void setDesign(int design) {
this.design = design;
}
@Override
public void getNotification(double yield) {
notifyByWeChat(weChat,yield);
}
public void produceVivoNex(int material,int design){
new Foxconn().produceCellPhone(material,design,this);//注册观察者
}
}
在这个例子中Oppo是不同的A类,它们都实现了回调接口CellPhoneCompany,实现了不同的回调方法getNotification;Foxconn是B类,A类中会调用Foxconn类的引用去调用B类中的方法(传入CallBack的引用作参数),而Foxconn类中执行完代工生产任务后会调用回调方法通知手机商它们的手机良品率。满足之前提到的回调机制的四个要求。
所以在这里可以给回调机制下个定义:A实现了回调接口,A想干一件事,委托给B去做,B做完后回调A的回调函数通知处理结果;对于回调接口的不同实现体现了回调机制的灵活性。
我们反过来看监听器那个例子:onClick是回调函数,OnClickListener是回调接口,MainActivity是A,Button是B。所以说监听器使用的就是回调机制。
3.观察者模式
观察者模式在这儿不做详细解释,可以参考《Head First 设计模式》。简单可以理解为:观察者模式=主题+观察者;主题和观察者是一对多的关系;一旦主题的状态发生变化,就通知所有的观察者。
监听器例子中:View是抽象主题,Button是具体主题,OnClickListener是一种观察者接口,MainActivity是观察者的具体实现。
回调例子中:Foxconn**(B)是主题**,Oppo和Vivo的实例**(A)是观察者**,一对多的关系;yield为主题状态。
yield=getYield(material,design);//主题状态发生变化
cellPhoneCompany.getNotification(yield);//通知观察者
上面代码可以理解为主题状态发生变化通知观察者。