奇特:子线程的Toast怎么显示不出来?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了奇特:子线程的Toast怎么显示不出来?相关的知识,希望对你有一定的参考价值。

我在子线程的run()中想显示Toast:……Toast.makeText(MainActivity.this,"This is a toast~~",Toast.LENGTH.SHORT).show();Log.d(TAG, "has excuted here~~");……发现log都显示出来了,但是Toast显示不出来,请教下大家,是什么原因?

因为Toast在创建的时候会依赖于一个Handler,并且一个Handler是需要有一个Looper才能够创建,而普通的线程是不会自动去创建一个Looper对象,比如说在某个Activity中能new一个Handler是因为android系统在启动一个Activity的时候会默认的创建一个Looper对象,因此不能够在子线程中显示Toast,你可以在开启的子线程中执行Looper.prepare()来构建一个Looper,然后在显示Toast,但是不要忘记执行Looper.loop()来加载这个Looper,当然,也可以使用主线程的Looper,获取主线程的Looper的方法是Looper.getMainLooper();同时需要注意的是,同样的不能在子线程中去更新UI界面,因为Toast是相对独立于UI界面的,就好比应用虽然crash掉了,并且已经返回到home界面,但是Toast依然会在hone界面显示出来。 参考技术A 晕,在子线程不能操作任何组件,你调用activity方法里面的runOnUIThread()就可以toast了 参考技术B 在Toast前调用loop.prare之后调用loop.looper。就可以了。 参考技术C Looper.prepare(); Toast.makeText(getActivity(), "十秒钟后", Toast.LENGTH_SHORT) .show(); Looper.loop(); 参考技术D 子线程里不能做此类操作,你在handler里面做toast显示塞!!

[Java Concurrent] 多线程合作 producer-consumers / queue 的简单案例

在多线程环境下,通过 BlockingQueue,实现生产者-消费者场景。

 

Toast 被生产和消费的对象。

ToastQueue 继承了 LinkedblockingQueue ,用于中间存储 Toast 。

Producer 生产 Toast ,并将生产出来的 Toast 放进队列 initialToastQ 中。

Processor 加工 Toast,从 initialToastQ 中获得生产出来的 Toast,将其加工并放进队列 finishedToast 中。

Consumer 消费 Toast,从 finishedToastQ 中获得加工完成的 Toast。

ThreadHelper 工具类,用于输出线程相关信息。

ProducerConsumerDemo 演示这个场景

 

 

代码实现:

Toast 实现

public class Toast {
    
    private int id;
    
    public Toast(int id){
        this.id = id;
    }

    public String toString(){
        return " toast#" + id;
    }
}

ToastQueue 实现

import java.util.concurrent.LinkedBlockingQueue;

public class ToastQueue extends LinkedBlockingQueue<Toast> {
    private static final long serialVersionUID = 1L;
}

Producer 循环生产 Toast

import java.util.concurrent.TimeUnit;

public class Producer implements Runnable {

    private ToastQueue toastQueue;
    private int count;
    
    public Producer(ToastQueue toastQueue){
        this.toastQueue = toastQueue;
        this.count = 0;
    }
    
    @Override
    public void run() {
        try {
            while (true){
                TimeUnit.MILLISECONDS.sleep(100);
                
                Toast toast = new Toast(count);
                count++;
                toastQueue.put(toast);
                ThreadHelper.print(" produced " + toast);
            }
        }catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

Processor 从 intialToastQ 获得 Toast ,对其加工,并放进 finishedToastQ 中。

import java.util.concurrent.TimeUnit;

public class Processor implements Runnable {

    private ToastQueue initialToastQ;
    private ToastQueue finishedToastQ;
    
    
    public Processor(ToastQueue initialToastQ, ToastQueue finishedToastQ){
        this.initialToastQ = initialToastQ;
        this.finishedToastQ = finishedToastQ;
    }
    
    @Override
    public void run() {
        try {
            while (true){
                Toast toast = initialToastQ.take();
                
                ThreadHelper.print(" processing " + toast);

                TimeUnit.MILLISECONDS.sleep(180);
                
                finishedToastQ.put(toast);
            }
        }catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

Consumer 消耗 Toast

public class Consumer implements Runnable {

    private ToastQueue finishedToastQ;

    public Consumer(ToastQueue finishedToastQ){
        this.finishedToastQ = finishedToastQ;
    }
    
    @Override
    public void run() {
        try {
            while (true){
                Toast toast = finishedToastQ.take();
                ThreadHelper.print(" consumed " + toast);
            }
        }catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

ThreadHelper 线程帮助类

public class ThreadHelper {    
    public static void print(String msg){
        System.out.println("[" + Thread.currentThread().getName() + " ] " + msg);
    }
}

演示烤面包的生产、加工、消费的场景

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

public class ProducerConsumerDemo {

    public static void main() throws InterruptedException{
        
        ToastQueue initialToastQ = new ToastQueue();
        ToastQueue finishedToastQ = new ToastQueue();
        
        ExecutorService exec = Executors.newCachedThreadPool();
        exec.execute(new Producer(initialToastQ));
        exec.execute(new Processor(initialToastQ, finishedToastQ));
        exec.execute(new Consumer(finishedToastQ));

        TimeUnit.SECONDS.sleep(2);
        exec.shutdownNow();
    }
}

 

 

输出结果:

[pool-1-thread-2 ]  processing  toast#0
[pool-1-thread-1 ]  produced  toast#0
[pool-1-thread-1 ]  produced  toast#1
[pool-1-thread-2 ]  processing  toast#1
[pool-1-thread-3 ]  consumed  toast#0
[pool-1-thread-1 ]  produced  toast#2
[pool-1-thread-1 ]  produced  toast#3
[pool-1-thread-2 ]  processing  toast#2
[pool-1-thread-3 ]  consumed  toast#1
[pool-1-thread-1 ]  produced  toast#4
[pool-1-thread-1 ]  produced  toast#5
[pool-1-thread-2 ]  processing  toast#3
[pool-1-thread-3 ]  consumed  toast#2
[pool-1-thread-1 ]  produced  toast#6
[pool-1-thread-1 ]  produced  toast#7
[pool-1-thread-2 ]  processing  toast#4
[pool-1-thread-3 ]  consumed  toast#3
[pool-1-thread-1 ]  produced  toast#8
[pool-1-thread-2 ]  processing  toast#5
[pool-1-thread-3 ]  consumed  toast#4
[pool-1-thread-1 ]  produced  toast#9
[pool-1-thread-1 ]  produced  toast#10
[pool-1-thread-2 ]  processing  toast#6
[pool-1-thread-3 ]  consumed  toast#5
[pool-1-thread-1 ]  produced  toast#11
[pool-1-thread-1 ]  produced  toast#12
[pool-1-thread-2 ]  processing  toast#7
[pool-1-thread-3 ]  consumed  toast#6
[pool-1-thread-1 ]  produced  toast#13
[pool-1-thread-1 ]  produced  toast#14
[pool-1-thread-2 ]  processing  toast#8
[pool-1-thread-3 ]  consumed  toast#7
[pool-1-thread-1 ]  produced  toast#15
[pool-1-thread-1 ]  produced  toast#16
[pool-1-thread-2 ]  processing  toast#9
[pool-1-thread-3 ]  consumed  toast#8
[pool-1-thread-1 ]  produced  toast#17
[pool-1-thread-2 ]  processing  toast#10
[pool-1-thread-3 ]  consumed  toast#9
[pool-1-thread-1 ]  produced  toast#18
java.lang.InterruptedException
    at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.reportInterruptAfterWait(AbstractQueuedSynchronizer.java:2014)
    at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2048)
    at java.util.concurrent.LinkedBlockingQueue.take(LinkedBlockingQueue.java:442)
    at concurrencyProducerConsumer.Consumer.run(Consumer.java:15)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at java.lang.Thread.run(Thread.java:745)
java.lang.InterruptedException: sleep interrupted
    at java.lang.Thread.sleep(Native Method)
    at java.lang.Thread.sleep(Thread.java:340)
    at java.util.concurrent.TimeUnit.sleep(TimeUnit.java:386)
    at concurrencyProducerConsumer.Producer.run(Producer.java:19)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at java.lang.Thread.run(Thread.java:745)
java.lang.InterruptedException: sleep interrupted
    at java.lang.Thread.sleep(Native Method)
    at java.lang.Thread.sleep(Thread.java:340)
    at java.util.concurrent.TimeUnit.sleep(TimeUnit.java:386)
    at concurrencyProducerConsumer.Processor.run(Processor.java:24)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at java.lang.Thread.run(Thread.java:745)

 

参考资料

Page 868, Produer-consumers and queue, Thinking in Java

 

以上是关于奇特:子线程的Toast怎么显示不出来?的主要内容,如果未能解决你的问题,请参考以下文章

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

Android子线程进度条不显示的问题

子线程怎么不阻塞主线程

如何使“主线程”等待“子线程”执行结束后再继续执行

主线程创建了子线程,怎么让主线程退出,而子线程仍然运行

QT中UI主窗口如何与子线程相互传递参数