前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Toast在子线程调用的问题

Toast在子线程调用的问题

作者头像
PhoenixZheng
发布2018-08-07 16:47:11
7350
发布2018-08-07 16:47:11
举报

Toast我们平时经常使用,但是你是否了解在子线程中要如何使用Toast呢?

Toast的一般姿势

平时我们经常在主线程中直接使用Toast,代码看起来会像下面这样

代码语言:javascript
复制
Toast.makeText(MainActivity.this, "", Toast.LENGTH_SHORT).show();

但是如果在子线程调用是不会有toast弹出的

Toast的正确姿势

如果在子线程调用那么让Toast能正常显示的方式是在它之前和之后调用Looper.prepare()和Looper.loop()

代码语言:javascript
复制
Looper.prepare();
Toast.makeText(MainActivity.this, "", Toast.LENGTH_SHORT).show();
Looper.loop();
原因是什么呢

我们得从源码角度来分析,看看在Toast show()的时候做了些什么

代码语言:javascript
复制
public void show() {
    if (mNextView == null) {
        throw new RuntimeException("setView must have been called");
    }

    INotificationManager service = getService();
    String pkg = mContext.getOpPackageName();
    TN tn = mTN;
    tn.mNextView = mNextView;

    try {
        service.enqueueToast(pkg, tn, mDuration);
    } catch (RemoteException e) {
        // Empty
    }
}

所以Toast其实是通过NotificationManagerService来实现Toast的展示的,而传给他的参数里的 mTn又是什么呢, 其实它是Toast的一个内部类,它有两个方法,show()和hide()是用来给NotificationManagerService回调的,可以看看它的代码

代码语言:javascript
复制
private static class TN extends ITransientNotification.Stub {
    ....
    /**
     * schedule handleShow into the right thread
     */
    @Override
    public void show(IBinder windowToken) {
        if (localLOGV) Log.v(TAG, "SHOW: " + this);
        mHandler.obtainMessage(SHOW, windowToken).sendToTarget();
    }

    /**
     * schedule handleHide into the right thread
     */
    @Override
    public void hide() {
        if (localLOGV) Log.v(TAG, "HIDE: " + this);
        mHandler.obtainMessage(HIDE).sendToTarget();
    }

因此可以看出来,Toast通过 NotificationManagerService来统一调度 Toast,而 NotificationManagerService回调 TN 的show()来往对应的线程发消息,

既然是handler实现,那么来看看它的实现代码,就在TN的构造方法里有这么一段

代码语言:javascript
复制
if (looper == null) {
    // Use Looper.myLooper() if looper is not specified.
    looper = Looper.myLooper();
    if (looper == null) {
        throw new RuntimeException(
                "Can't toast on a thread that has not called Looper.prepare()");
    }
}
mHandler = new Handler(looper, null) {....

因此没有调用prepare()和启动消息队列的话,在子线程调用Toast是显示不出来的。

总结

Toast在主线程的显示只需要调用show()就可以,如果想在子线程调用,则需要在子线程启动Looper,这样才能有消息队列来承载Handler收发消息。否则子线程的Toast是不能显示的

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2018-03-16,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Android每日一讲 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Toast的一般姿势
  • Toast的正确姿势
  • 原因是什么呢
  • 总结
相关产品与服务
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档