内容简介:

  1. 接口回调的理解及需要关注的问题
  2. 接口回调一般常规用法
  3. 接口回调简洁用法
  4. 接口回调的意义

接口回调简介:

简单的说接口回调就是:调用者A类访问了被调用者B类中的M方法.这个M方法在执行完毕后又调用了A类中的方法.

问题?

B类中的M方法是如何访问A类中的方法的呢?弄清了这个问题,也就明白了接口回调.

下面我们根据一个场景描述去编写代码:

我们在调用者Caller类中使用被调用者Collee类中的下载文件方法DownLoadFile().下载完成后要通知Caller类文件加载完成.这个时候Caller类才能去访问刚才下载的资源.由于下载需要时间.而Caller类还有其他事情要做.不能等着下载完成后再去做.这样的话下载的方法必须开启新的线程去下载.

接口回调一般常规用法

代码实现:1.接口和回调方法:

/*
CallBackListener (回调监听接口)
用于回调的接口 (接口内的抽象方法用于监听被调用者返回的结果)
接口中有回调方:该回调方法是被调用者通过回调接口对象去访问调用者的方法.所以形参应该是被调用者返回给调用者结果的数据类型和参数个数。
*/
public interface CallBackListener {
    //发送消息给调用者
    public abstract void sendMessage2Caller(String msg);
}

2.调用者类:

/*
Caller :(调用者)
调用者在访问被调用者的方法前.必须将回调接口对象设置给被调用者.以方便被调用者使用接口回调对象访问自己.
*/
public class Caller {
    public static void main(String[] args) {
        //1.创建被调用者对象
        Callee callee = new Callee();
        
        //2.创建回调接口对象.
        CallBackListener cb = new CallBackListener() {
            
            @Override
            public void sendMessage2Caller(String msg) {
                //打印回调传递过来的结果
                System.out.println(msg);
                
            }
        };
        
        //3.必须将回调接口对象设置给被调用者
        callee.setCallBackListener(cb);
        
        //4.访问被调用者的下载文件方法.这个方法完成后被调用者会通过回调接口对象通知我们.
        callee.DownLoadFile();
        
        System.out.println("你下载真慢,我先去忙别的事了....");
    }
}

3.被调用者类

/*
Callee(被调用者):
1.被调用者类中必须有回调接口类型的变量.
2.并且还要有给该变量赋值的setXxx()方法.
3.在可以给调用者返回结果的时候.拿着接口类型的变量调用接口的方法进行对调用者的访问.(因为接口类型的变量要执行的方法在调用者那里存在).
*/
public class Callee {
    //1.被调用者类中必须有 回调接口类型的变量.
    private CallBackListener cb;
    
    //2.并且还要有给该变量赋值的setXxx()方法.
    public void setCallBackListener(CallBackListener cb){
        this.cb = cb;
    }
    
    /**
    * 下载文件是非常耗时的工作.而调用者又需要在下载完成后读取下载的文件.
    * 所以当这个方法完成下载后应该立刻通知调用者.这个通知的动作就称之为回调.
    * @throws InterruptedException 
    */
    public void DownLoadFile(){
        //开启新的线程去下载.异步任务.
        new Thread(){
            public void run() {
                long start = System.currentTimeMillis();
                
                //使用睡眠模拟耗时工作.
                try {
                    Thread.sleep(5000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                
                long end = System.currentTimeMillis();
                
                //完成下载后通知调用者
                if(cb != null){
                    cb.sendMessage2Caller("下载完成,耗时:"+(end-start)/1000+"秒,你可以去访问资源了.");
                }
            };
        }.start();
    }
}

运行结果如下:


5秒钟后


接口回调简洁用法

代码实现:

1.接口和回调方法:

/*
CallBackListener (回调监听接口)
用于回调的接口 (接口内的抽象方法用于监听被调用者返回的结果)
接口中有回调方:该回调方法是被调用者通过回调接口对象去访问调用者的方法.所以形参应该是被调用者返回给调用者结果的数据类型和参数个数。
*/
public interface CallBackListener {
    //发送消息给调用者
    public abstract void sendMessage2Caller(String msg);
}

2.调用者类:

public class Caller {
    public static void main(String[] args) {
        //1.创建被调用者对象
        Callee callee = new Callee();
        //2.访问被调用者的下载文件方法.这个方法完成后被调用者会通过回调接口对象通知我们.
        //使用匿名内部类对象当做参数传递.更加简洁
        callee.DownLoadFile(new CallBackListener() {
        
            @Override
            public void sendMessage2Caller(String msg) {
                //打印回调传递过来的结果
                System.out.println(msg);
            }
        });
        
        System.out.println("你下载真慢,我先去忙别的事了....");
    }
}

3.被调用者类

/**
* 下载文件是非常耗时的工作.而调用者又需要在下载完成后读取下载的文件.
* 所以当这个方法完成下载后应该立刻通知调用者.这个通知的动作就称之为回调.
* final CallBackListener cb 匿名内部类访问局部变量必须加final.
*/      
public class Callee {
    public void DownLoadFile(final CallBackListener cb){
        //开启新的线程去下载.异步任务.
        new Thread(){
            public void run() {
                long start = System.currentTimeMillis();
                
                //使用睡眠模拟耗时工作.
                try {
                    Thread.sleep(5000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                
                long end = System.currentTimeMillis();
                
                //完成下载后通知调用者
                if(cb != null){
                    cb.sendMessage2Caller("下载完成,耗时:"+(end-start)/1000+"秒,你可以去访问资源了.");
                }
                
            };
        }.start();
    }
}

接口回调的意义:

通过以上两个案例大家会不会有一个疑问.为什么要搞一个接口呢?把接口换成普通的类可以吗?当然是可以的.这里之所以使用接口回调.是因为接口具有规范性和灵活性.特别是规范性.

代码举例:

1.原来的接口换成抽象类其他两个类不变, 不会影响运行效果

public abstract class CallBackListener {
    //发送消息给调用者
    public abstract void sendMessage2Caller(String msg);
}

2.原来的接口换成类其他两个类不变, 不会影响运行效果public class CallBackListener {

//发送消息给调用者
public void sendMessage2Caller(String msg){

};
 }