有这样一句话“接口的回调机制和向上转型是设计模式解耦的核心”可见回调是多么重要,而且回调在安卓源码也屡见不鲜。
什么是回调?
栗子引申
简单的举例来说就是小明想让小华帮自己做作业,于是小明就把自己的作业本给小华了,可是不知道小华是否给自己做了,于是要求小华两天后吧作业本归还。自己收到作业本上多了好多内容就证明小明帮自己做了。
模型图
类设计
1、作业本
package homework;
/**
* Create by SunnyDay on 2019/03/06
*/
public interface Inote {
void finish();
void unFinish();
}
作业本是一个接口,两者之间交流的纽带
2、小明要做的事
package homework;
/**
* Create by SunnyDay on 2019/03/06
*/
public class DoHomeWork {
/**
*小明的作业
*/
public static void homeWorkofMing(boolean isFinish, Inote inote) {
if (inote!= null) {
// 处理回调
if (isFinish) {
inote.finish();
System.out.println("收到,谢谢你帮我完成!!!");
} else {
inote.unFinish();
System.out.println("收到 ,没完成也没关系!!!");
}
}
}
}
小明就提供了个作业本(Inote)和待收信息(isFinish),然后自己预处理下,如果小华收到作业本又给我写好了我就谢谢他,如果收到作业本但是没给我写好我就安慰他没关系。
3、小华要做的事
package homework;
/**
* Create by SunnyDay on 2019/03/06
*/
public class Test {
public static void main(String[] args) {
DoHomeWork.homeWorkofMing(false, new Inote() {
@Override
public void finish() {
// 完成了时,传true
}
@Override
public void unFinish() {
// 此时触发接口中的unFinish方法,
System.out.println("抱歉我没完成");
}
});
}
}
小华给出作业完成了还是没完成回复
安卓中的回调
众所周知安卓中的View都有点击事件,其实点击事件背后就是接口的回调处理。
1、信手拈来的view点击事件
Button btn = findViewById(R.id.btn);
btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Log.i(TAG, "onClick: 1111");
Toast.makeText(TestActivity.this, "普通按钮", Toast.LENGTH_SHORT).show();
}
});
2、点击事件源码–View.java
...略
// View的内部类
static class ListenerInfo {
public OnClickListener mOnClickListener;
...略
}
...略
public void setOnClickListener(@Nullable OnClickListener l) {
// 检测控件的Clickabke 属性
if (!isClickable()) {
// 触发点击事件时吧Clickabke 设置为true
setClickable(true);
}
// 主要看这里:吧用户传递过来的接口实现对象赋值给本地成员变量(mOnClickListener)
getListenerInfo().mOnClickListener = l;
}
public interface OnClickListener {
/**
* 用户点击view时触发
*
* 参数:用户点击的view
*/
void onClick(View v);
}
3、再次练习回调
仿写点击事件实现我们自己的文字检测
思路 :自定义一个view(为了方便此处继承Button) 提供个文字检测的方法,检测是否给这个view设置了文字
简单自定义类 及其接口
package com.example.administrator.test.callbackdemo;
import android.content.Context;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.Log;
import android.widget.Button;
import static android.support.constraint.Constraints.TAG;
/**
* Create by SunnyDay on 2019/03/06
*/
public class CustomView extends Button {
public CustomView(Context context) {
super(context);
}
public CustomView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public CustomView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
/**
* 自定义点击事件
* */
public void setMyOwnClickListener(MyOwnListener myOwnListener) {
// 调用事件
if (myOwnListener !=null){
if (!TextUtils.isEmpty(this.getText().toString())){
myOwnListener.onSet();//用户点击view且设置了文字时触发
Log.i(TAG, "setMyOwnClickListener:收到 :你设置了文字 ");
}else{
myOwnListener.onUnSet();//用户点击view且没有设置了文字时触发
Log.i(TAG, "setMyOwnClickListener:收到 :你未设置的文字 ");
}
}
}
/**
* 接口
*
* 是否设置了文字
* */
public interface MyOwnListener {
void onSet();
void onUnSet();
}
}
测试
/**
* 文字设置监听
* */
CustomView customView = findViewById(R.id.customview);
customView.setMyOwnClickListener(new CustomView.MyOwnListener() {
@Override
public void onSet() {
// 设置文字时处理
}
@Override
public void onUnSet() {
Toast.makeText(TestActivity.this, "没有设置文字", Toast.LENGTH_SHORT).show();
}
});
大体总结
小结
安卓中使用最多的应该是RecyclerView设置item的点击事件啦,由于他不像ListView一样已经提供所以我们要手动实现。
大体思路:
1、写接口
2、类的内部搞个接口的引用
3、类的内部提供个对外方法(参数为接口的引用类型),对你声明接口引用赋值。
4、触发事件时,你通过接口的引用掉下接口方法即可。
经典的RecyclerView设置item的点击事件参考:RecyclerView为每个item添加点击事件
The end
相关参考:对java多态的一点感悟