📜  无法在未调用 looper.prepare() 的线程上敬酒 (1)

📅  最后修改于: 2023-12-03 15:40:07.487000             🧑  作者: Mango

无法在未调用 looper.prepare() 的线程上敬酒

如果你是Android开发者,很可能会遇到这个异常:

android.os.NetworkOnMainThreadException

这个异常的意思是“在主线程上进行了网络操作”,即在UI线程上进行了涉及到网络请求的操作,这会导致UI线程被阻塞,造成卡顿等不良用户体验。

为了避免这个问题,在Android中一般都会使用异步方式进行网络请求,比如使用AsyncTask、Handler、Thread等。

但是,在使用这些异步操作时,会遇到另一个异常:

java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()

这个异常的意思是“在线程中创建Handler时未调用Looper.prepare()”,即在非UI线程中创建Handler时,必须先调用Looper.prepare()方法,然后再创建Handler。否则,就会导致上述异常的抛出。

那么,为什么要使用Looper和Handler呢?

在Android中,每个线程都拥有自己的Message Queue(消息队列)和Looper(消息循环器),用于处理消息事件。而Handler则是用于向Message Queue发送消息,并且处理消息回调的机制。

在UI线程中,系统自动完成Looper和Handler的初始化,因此我们可以直接使用Handler来处理消息事件。但是,在非UI线程中,由于缺少Looper和Handler,我们需要手动初始化Looper,并创建Handler。

下面是一个使用Handler进行异步网络请求的示例代码:

public class NetworkTask implements Runnable {
    @Override
    public void run() {
        // 初始化Looper
        Looper.prepare();

        // 创建Handler
        Handler handler = new Handler() {
            @Override
            public void handleMessage(Message msg) {
                // 在这里处理消息事件
            }
        };

        // 执行网络请求
        // ...

        // 发送消息到Message Queue中
        handler.sendMessage(msg);

        // 释放Looper
        Looper.loop();
    }
}

在上述代码中,我们先调用了Looper.prepare()方法来初始化Looper,然后创建了Handler,并在处理完网络请求后,向Message Queue发送了一个消息。最后,我们通过调用Looper.loop()方法来启动消息循环器,实现异步处理网络请求的目的。

总结一下,使用Looper和Handler进行异步处理时,必须保证在非UI线程中先调用Looper.prepare()方法来初始化Looper,然后再创建Handler。否则,就会出现“java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()”这样的异常。

在Android开发中,正确使用Looper和Handler机制,可以在保证UI线程流畅的同时,完成异步处理任务。