这是我参与8月更文挑战的第 5 天,活动详情查看:8月更文挑战
前言
在 Android 开发中,遇到的很多回调情况都是异步回调,比如访问网络、访问本地文件或数据库等等,在子线程中进行这些操作,然后等结果返回后,再来到主线程进行 UI 更新等动作。这也是习以为常的事情了,那么如何将这种异步回调改成同步式的回调呢,今天就来说说我所了解到的方法。
基本介绍
首先我们定义一个异步回调
public class MyEvent {
public void testSleep(EventListener listener) {
new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
listener.onEvent("Hello");
}
}).start();
}
interface EventListener {
void onEvent(String msg);
}
}
然后定义主方法
public class MainTest {
public static void main(String[] args) {
System.out.println("Start ...");
MyEvent event = new MyEvent();
event.testSleep(new MyEvent.EventListener() {
@Override
public void onEvent(String msg) {
System.out.println("Message ..." + msg);
}
});
System.out.println("End ...");
}
}
这时候我们来看一下打印的输出
Start ...
End ...
Message ...Hello
可见回调返回的结果是会在主流程结束后再出现的,现在我们将其改造成同步形式的。
同步锁机制实现
回调部分不用动,我们修改主方法
public class Main {
public static void main(String[] args) {
Object object = new Object();
System.out.println("Start ...");
MyEvent event = new MyEvent();
synchronized (object) {
event.testSleep(new MyEvent.EventListener() {
@Override
public void onEvent(String msg) {
System.out.println("Message ..." + msg);
synchronized (object) {
object.notify();
}
}
});
try {
object.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("End ...");
}
}
这里在执行这个回调方法的时候,使用 synchronized 进行加锁操作,然后在回调方法后调用 wait() 方法,进行阻塞等待。在回调方法里面我们调用 notify() 来通知到等待锁的对象。这样因为 wait() 会一直阻塞直到 notify() 的调用才会继续执行。这样就实现了同步阻塞式的调用。
CountDownLatch 方法实现
继续修改主方法,关于 CountDownLatch 的使用见下方参考部分。
public class MainOther {
public static void main(String[] args) {
CountDownLatch controller = new CountDownLatch(1);
System.out.println("Start ...");
MyEvent event = new MyEvent();
event.testSleep(new MyEvent.EventListener() {
@Override
public void onEvent(String msg) {
System.out.println("Message ..." + msg);
controller.countDown();
}
});
try {
controller.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("End ...");
}
}
这里我们先新建一个 CountDownLatch 对象,计数器设为 1,然后进行 await() 等待,在回调内部方法执行后,将计数器减 1,当计数器变为 0 的时候,CountDownLatch 类将唤醒所有调用 await() 方法并进入 WAITING 状态线程。所以这样也就实现了同步方法改成异步方法。
总结
当然这里只是简单总结了怎么使用,具体的原理和更多方法还需要进一步学习。