首先,什么是异步呢?异步其实是和同步相对应的一个概念,他们是一种消息通讯机制,关注的是执行过程和结果返回方式。同步的话,在没有得到结果之前,始终是不返回请求的,但是一旦请求返回,就得到返回值了。异步的话则相反,当你发送一个请求后,请求就返回了,但是并没有立刻得到返回结果,需要被请求者通过某种方式(比如回调)来告诉请求者结果。编程都是源于生活,我们举个例子:

      假设我要买一部可以当炸弹的手机,我打电话问sam啥手机店的老板,如果有的话,老板会立刻告诉我,有啊noo7就行了;不清楚的时候,他可能告诉我,你等会我查下,然后查啊查,可能查了四五秒,也可能查了四五分钟,然后就告诉我结果(请求返回,立刻有返回结果)。这就是同步了。

      同样是上述的情况,我问老板有可以当炸弹的手机吗,老板不确定,就和我说,我待会查下,查到了再打电话告诉你,然后电话挂断了(不返回结果)。第二天,老板打电话告诉我,这手机给禁了,买不到了(回调)。这就是异步了。

      PS:从上面例子也可以看出,同步和异步是不能和阻塞和不阻塞混为一谈的,我们同步阻塞的时候就会出现ANR了。

      好,为了更好的理解,那么我们现在来写代码。首先是同步机制,书店老板有一个checkPhone()方法可以检查是否有我们要的手机。

public class PhonestoreService {

    public boolean ckeckPhone(String phoneName) {
        boolean result = "noo7".equals(phoneName);
        return  result;
    }
}




      接下来我们要打电话给sam啥手机店老板,我们在MainActivity的布局文件中定义了一个按钮,点击时打电话给书店老板询问是否有手机,然后打印结果:

@OnClick(R.id.btnCall)
public void onClick() {
    // 打了电话给手机店老板,要老板告诉是否有手机
    boolean result = service.ckeckPhone("noo7");
    Log.i("result: ", result +"");
}




      我们运行一下,得到下面的结果:

      

harmonyos 异步回调 异步与回调_harmonyos 异步回调

      这时大家就要吐槽了,这谁不会,我刚学java基础的时候就会了,别急,后面完全看懂了才叫做会。

      假设手机店老板手机型号太多了,不知道有没有你要的手机,他需要打开电脑的数据库查一下,这可能需要花费一点儿时间,这时候我们在checkPhone()方法里面加上一点代码:

public boolean ckeckPhone(String phoneName) {
    SystemClock.sleep(2000);
    boolean result = "noo7".equals(phoneName);
    return  result;
}




      相信大家看到代码都知道点击按钮时,按钮有两秒变成不可点击的状态,如果把sleep()时间变为5000毫秒或者更久,这里还会出现一个ANR的错误。这时大家要说了,那还不简单,开个线程呗,于是有了下面的代码(下面代码有内存泄露的风险哦,同学们可以自己分析下):

/**
 * 异步实现
 * @param phoneName
 * @return
 */
public boolean checkPhone1(final String phoneName) {
    new Thread() {
        @Override
        public void run() {
            SystemClock.sleep(2000);
            result = "noo7".equals(phoneName);
        }
    }.start();
    return result;
}




      这时候我们看下Log日志会发现,咦,第一次请求结果是false,2秒后再请求一次结果是true了(下面是连续点击的效果):

      

harmonyos 异步回调 异步与回调_异步_02

      其实到这里,我们就开启了异步请求了,简单分析下:我们在开启线程的时候,第一次返回的是result的默认值,而第二次发起请求时,实际上是返回给我们的结果是第一次请求时线程里面2秒后赋值的result,为true。那么现在我们想请求后,对方给我们返回正确的结果。怎么办呢?这时候就要用到监听回调了。

      好了,这时候我们给店主留了号码,然后让他查到结果以后再告诉我们,接下来我们就去做自己的事情了。这里我们在MainActivity中定义了一个方法onResultGet(),店主查到结果就会调用这个方法(打电话过来):


/**
 * 有结果了,接电话
 *
 * @param result
 * @return
 */
public boolean onResultGet(boolean result) {
    return result;
}



      而在店主那里,要有我的联系方式(占有了我的引用):


/**
 * 异步回调
 * @param phoneName
 * @param activity 我的引用
 */
public void ckeckPhoneAsyn(final String phoneName,
        final MainActivity activity) {

    new Thread() {
        @Override
        public void run() {
            SystemClock.sleep(2000);
            boolean resultAsyn = "noo7".equals(phoneName);
            // 查到结果了,要告诉顾客,等顾客接电话
            activity.onResultGet(resultAsyn);
        }
    }.start();
}



      这时候我们再运行一下看看结果:

      

harmonyos 异步回调 异步与回调_异步_03

      但是,这依然不是最好的。相信用过框架的同学都知道,我们不会直接在ckeckPhoneAsyn()中直接传个当前对象this(即固定的对象)进来,因为这里一旦我们变成了别的对象,这个方法就废了。这时候我们就要有一种面向接口编程的思想了!我们直接在PhonestoreService中定义一个接口:


public interface onResultGetListener {
    void onSuccess(boolean result);
    void onFail();
}

      接口里面有两个方法,分别在成功返回结果和返回结果失败的时候进行相应的动作(比如老板因为店里有太多sam啥手机,炸了,没办法告诉你结果)。这时候,只要我们的Mainactivity实现这个接口,然后在这两个方法里面做相应的业务处理就可以了。下面是面向接口编程思想后的形式,第二种看着是不是很像onClickListener()呢?其实道理是一样的。


service.ckeckPhoneAsynCallback("not7", MainActivity.this);
service.ckeckPhoneAsynCallback("noo7", new PhonestoreService.onResultGetListener() {
    @Override
    public void onSuccess(boolean result) {

    }

    @Override
    public void onFail() {

    }
});