java回调callback

callback不在23中设计模式之中,但我觉得它和设计模式一样重要。

大家都知道异步IO比同步IO性能更好,唯一的问题就是异步IO不能马上获得返回结果。

一般通过一个callback来获取返回值。我们通过一个简单的异步IO例子,来理解下callback的应用。

首先我们实现一个客户端,它负责发送消息

public class AsyncHttpClient {

   private Connection connect(String host, int port) {
        return new Connection(host, port);
    }

    public void sendMsg(String host, int port, String msg, final InvokeCallback invokeCallback) {
        Connection connection = connect(host, port);
        Command command = new Command(msg);
        boolean sendOk = connection.send(command);
        ResponseFuture future = new ResponseFuture(command,invokeCallback);
        if (sendOk) {
            future.executeInvokeCallback();
        }
    }

    public static void main(String[] args) {
        AsyncHttpClient httpClient = new AsyncHttpClient();
        httpClient.sendMsg("hw-node4", 9090, "hello?", new InvokeCallback() {
            @Override
            public void operationComplete(ResponseFuture future) {
                String s = future.get();
                System.out.println("receive="+s);
            }
        });
    }
}

消息的内容,我们包装了一个Command类

public class Command {
    private static final AtomicLong idGenerator = new AtomicLong(1);
    private Long requestId;
    private String msg;

    public Command(String msg) {
        this.requestId = idGenerator.getAndIncrement();
        this.msg = msg;
    }

    @Override
    public String toString() {
        return "msg='" + msg ;
    }
}

为了建立和服务端的连接,我们还需要一个Connection类

public class Connection {
    private String host;
    private int port;

    public Connection(String host, int port) {
        this.host = host;
        this.port = port;
        System.out.println("init Connection");
    }

    boolean send(Command msg) {
        System.out.println("send=" + msg.toString());
        try {
            Thread.sleep(1000);
            return true;
        } catch (InterruptedException e) {
            e.printStackTrace();
            return false;
        }
    }
}

因为是异步IO,所以发送完消息后,会生成一个Future对象。

理论上Future对象会跟服务端交互,在未来的某一个时刻拿到时间的response,但这里我们没有实际的服务端,所以就简单返回一个OK。

public class ResponseFuture {
    private final Command msg;
    private final InvokeCallback invokeCallback;

    public ResponseFuture(Command msg, InvokeCallback invokeCallback) {
        this.msg = msg;
        this.invokeCallback = invokeCallback;
    }

    public String get() {
        return msg + ",ok!";
    }

    /**
     * 执行回调函数
     */
    void executeInvokeCallback() {
        invokeCallback.operationComplete(this);
    }
}

回调接口也很简单,它给我们返回Future对象

public interface InvokeCallback {
    void operationComplete(ResponseFuture future);
}

这样我们在sendMsg的同时,传入一个InvokeCallback,里面有一个operationComplete方法,方法的内容使我们自定义的。

一旦我们成功收到response,就会执行这个回调函数。

 

另外一种回调的使用场景是前端。

比如页面上设计了一个按钮,但按钮并不知道用户点击后需要自己干什么,所以还需要传入一个回调函数。里面包着需要做的事情

Button button = (Button)findViewById(R.id.button);
button.setOnClickListener(new OnClickListener() {
  @Override
  public void onClick(View v) {
    System.out.println("I am clicked.");
  }
});

 

posted @ 2022-01-25 11:17  Mars.wang  阅读(342)  评论(0编辑  收藏  举报