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