编程史上有两个令人匪夷所思的说辞,一个是订阅,一个是回调函数。
我想应该还有很多同学为“事件的订阅”和“回调函数”所困扰,因为事情本来就不应该按这个套路来解释。
多直白,所谓的“回调函数”你完全可以线性的理解它,现在起,你只需要知道“接口”与“实现”!
常见的场景如下:
1.我写了个模块,模块中有一些功能要实现,但我暂时没空做,或者需要他人的协助来完成具体的实现。因此我先定义一个接口,接口中根据我的需要定义一些空方法,在我的模块中调用这些空方法,这些方法的具体实现交给未来实现该接口的类中去实现。
2.我写的是可复用的控件,例如点击它会完成什么功能,需要使用他的人到时候自行去填写。因此我先定义一个接口,接口中根据我的需要定义一些空方法,在我的控件中调用这些空方法,这些方法的具体实现交给未来实现该接口的类中去实现。
3.我在设计模块,就像罗列大纲一样,在接口中把该有的方法大致罗列出来,然后由实现这个接口的类来实现这些方法。
4.我写了个模块,有些功能适合放在特定的类中去实现。因此我先定义一个接口,接口中根据我的需要定义一些空方法,在我的模块中调用这些空方法,这些方法的具体实现交给未来实现该接口的类中去实现。
……
有没有发现,尽管出于不同的目的,但是他们的套路都是一样的:
1.定义接口,接口中定义空方法
2.在不方便或不适合实现方法的地方调用这些空方法
3.在实现该接口的类中具体实现这些方法
对于调用空方法的地方来说,他们调用未来会被实现的空方法,和直接调用一个现成的方法,效果是一样的。
可能光看文字描述并无助于你的理解,那么下面的代码,帮助你顺流直下秒懂这一切。
1.我写了一个可复用的控件,里面有个按钮的点击事件需要放在未来调用该控件的Activity中实现
public class TitleBar extends RelativeLayout { public TitleBar(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
} public TitleBar(Context context) {
super(context);
} public TitleBar(Context context, AttributeSet attrs) {
super(context, attrs); LayoutInflater.from(getContext()).inflate(R.layout.title_bar, this);
} private Button btnBack; private void initView() {
btnBack = (Button) this.findViewById(R.id.btn_back);
btnBack.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) { }
});
}
}
2.因此我定义一个接口,其中定义控件点击事件中要执行的方法的空方法,然后在控件的点击事件中调用该空方法。
public class TitleBar extends RelativeLayout { public TitleBar(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
} public TitleBar(Context context) {
super(context);
} public TitleBar(Context context, AttributeSet attrs) {
super(context, attrs); LayoutInflater.from(getContext()).inflate(R.layout.title_bar, this);
initView();
} private Button btnBack; private void initView() {
btnBack = (Button) this.findViewById(R.id.btn_back);
btnBack.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
//5.调用该接口的该空方法
mTitleBarListener.btnBackClick();
}
});
} //1.定义该接口
public interface TitleBarListener {
//2.定义该空方法
void btnBackClick();
} //3.在控件中定义一个该接口的成员变量
private TitleBarListener mTitleBarListener; //4.为该接口成员变量定义一个set方法,用于从实现类中传入接口的实例
public void setOnTitleBarListener(TitleBarListener titleBarListener) {
this.mTitleBarListener = titleBarListener;
}
}
3.在Activity中使用该控件,传入该接口的实例,并实现该方法
public class ActivityOne extends AppCompatActivity { @Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.aty_one);
initView();
} private TitleBar titleBar; private void initView() {
titleBar = (TitleBar) findViewById(R.id.titleBar);
//6.调用该接口的set方法,将接口的实例传入并具体实现控件中调用的空方法
titleBar.setOnTitleBarListener(new TitleBar.TitleBarListener() {
@Override
public void btnBackClick() {
//此处填充我们具体要实现的内容
}
});
}
}
怎么样,容易理解吧。未来我们一定还会遇到各种各样奇葩的说辞,需要你多实践,透过表象看其本质,这样就不能轻易的被迷惑了。