Android 开发中异步回调改成同步回调

1,641 阅读2分钟

这是我参与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 状态线程。所以这样也就实现了同步方法改成异步方法。

总结

当然这里只是简单总结了怎么使用,具体的原理和更多方法还需要进一步学习。