子线程无法弹出Toast吗?

1、在子线程中toast会报如下异常

Can't toast on a thread that has not called Looper.prepare()

2、要想在子线程中弹Toast需要 如下:结果就会在子线程中弹出Toast

    new Thread(new Runnable() {
            @Override
            public void run() {
                Looper.prepare();
                Toast.makeText(MainActivity.this, "my toast", Toast.LENGTH_SHORT).show();
                Looper.loop();

            }
        }).start();

3、解释以上现象
首先,Toast内部有两类IPC过程,第一类是Toast访问NotificationManagerService,第二类是NotificationManagerService回调Toast里面的TN接口。

    public void show() {
        if (mNextView == null) {
            throw new RuntimeException("setView must have been called");
        }
        // 此处使用到了系统服务,也就是一类IPC
        INotificationManager service = getService();
        String pkg = mContext.getOpPackageName();
        // TN是本地的Binder类,当NMS处理Toast的显示请求是会回调TN中的方法
        TN tn = mTN;
        tn.mNextView = mNextView;

        try {
            service.enqueueToast(pkg, tn, mDuration);
        } catch (RemoteException e) {
            // Empty
        }
    }
    private static class TN extends ITransientNotification.Stub {

            mHandler = new Handler(looper, null) {
                @Override
                public void handleMessage(Message msg) {
                    switch (msg.what) {
                        case SHOW: {
                            IBinder token = (IBinder) msg.obj;
                            handleShow(token);
                            break;
                        }
                        case HIDE: {
                            handleHide();
                            // Don't do this in handleHide() because it is also invoked by
                            // handleShow()
                            mNextView = null;
                            break;
                        }
                        case CANCEL: {
                            handleHide();
                            // Don't do this in handleHide() because it is also invoked by
                            // handleShow()
                            mNextView = null;
                            try {
                                getService().cancelToast(mPackageName, TN.this);
                            } catch (RemoteException e) {
                            }
                            break;
                        }
                    }
                }
            };
        }

        /** * 该方法会被NMS处理显示请求时候回调,由于该方法运行在binder线程池中 * 所以需要使用Handler将其切换到当前线程中 */
        @Override
        public void show(IBinder windowToken) {
            if (localLOGV) Log.v(TAG, "SHOW: " + this);
            mHandler.obtainMessage(SHOW, windowToken).sendToTarget();
        }

可以看到NMS回调TN中的show方法,show方法又运行在binder线程池中,所以使用了handler将其切换到当前线程中,而当前线程就是发送Toast请求所在的线程,而handler需要looper才能完成切换线程的功能。

    原文作者:CJ_Geek
    原文地址: https://blog.csdn.net/reuxfhc/article/details/80738401
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞