Android Toast在子线程中为什么无法正常使用

1.概述

在android中Toast经常会被用到,在主线程中直接使用Toast没任何问题,消息显示正常。一旦将Toast放入子线程中的时候,消息不会有任何响应。网上查了解决办法,直接将写在子线程中的Toast前后加上Looper.prepare(),其后加上Looper.loop(),就可以正常显示了。例:
                new Thread() {

                    @Override
                    public void run() {
                        Looper.prepare();
                        Toast.makeText(getApplicationContext(), "发生未知错误!", Toast.LENGTH_SHORT).show();
                        Looper.loop();
                    }
                }.start();

   原来一直是只知其然不知其所以然,现在就看下内在原理,彻底了解为什么。(不建议这么使用,会造成新的问题。当前子线程因为looper的存在,导致一直处于未销毁状态,而占有内存。建议直接将消息发送到UI线程中进行显示。)

2.Looper

首先,来了解下Looper。

看看关于looper这个类的描述说明。

  * Class used to run a message loop for a thread.  Threads by default do
  * not have a message loop associated with them; to create one, call
  * {@link #prepare} in the thread that is to run the loop, and then
  * {@link #loop} to have it process messages until the loop is stopped.
  *
  * <p>Most interaction with a message loop is through the
  * {@link Handler} class.

(大意就是,looper这个类是用来给线程thread运行消息循环的。线程们在默认情况下并没有一个消息循环loop与它们相关联;用looper类中的方法prepare可以在线程中创建一个looper对象用来执行loop用的,然后调用loop方法时就会让之前创建的looper对象来处理循环中的消息,直到循环停止。

Looper与消息循环的大部分交互是通过Handler类。)

看到这,就可以知道looper主要的方法就prepare()和loop()。

1.Looper.prepare()

   static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
   private Looper(boolean quitAllowed) {
        mQueue = new MessageQueue(quitAllowed);
        mThread = Thread.currentThread();
    }
    public static void prepare() {
        prepare(true);
    }

    private static void prepare(boolean quitAllowed) {
        if (sThreadLocal.get() != null) {//第5行
            throw new RuntimeException("Only one Looper may be created per thread");
        }
        sThreadLocal.set(new Looper(quitAllowed));
    }

从第5行可以看出Looper.prepare()方法中,首先会判断sThreadLocal中是否已经有Looper存在,如果有就抛异常,没有就实例化一个looper set进去。从这就可以看出每个线程中只可能存在一个Looper。

实例化Looper时,会创建一个MessageQueue,同时将当前线程和Looper绑定。

2.Looper.loop()

    public static void loop() {
        final Looper me = myLooper();
        if (me == null) {
            throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
        }
        final MessageQueue queue = me.mQueue;

        // Make sure the identity of this thread is that of the local process,
        // and keep track of what that identity token actually is.
        Binder.clearCallingIdentity();
        final long ident = Binder.clearCallingIdentity();

        for (;;) {
            Message msg = queue.next(); // might block
            if (msg == null) {
                // No message indicates that the message queue is quitting.
                return;
            }

            // This must be in a local variable, in case a UI event sets the logger
            final Printer logging = me.mL
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值