美文网首页Android 开发录
android 为什么只能在主线程更新View

android 为什么只能在主线程更新View

作者: 过期的薯条 | 来源:发表于2017-07-13 17:30 被阅读151次

    1.引言

    前几天去面试有过这样的问题。都知道在非ui线程中不能进行ui操作,但是为什么不能进行ui线程的操作。问的我不知所措。所以决定抽时间,看看博客 找找源码,看看为什么

    2.正题

    2.1ViewManager

    Paste_Image.png

    2.2WindowManager

    windowManager 是继承于ViewManager。所以windowManager里面存在addView()方法。

    Paste_Image.png

    2.3 WindowManager实现类WindowManagerImpl

    windowManager.addView() 实际调用的是WindowManagerGlobal.addView()

    Paste_Image.png

    2.4WindowManagerGlobal类

    Paste_Image.png

    addView方法的核心代码

    {
                // Start watching for system property changes.
                if (mSystemPropertyUpdater == null) {
                    mSystemPropertyUpdater = new Runnable() {
                        @Override public void run() {
                            synchronized (mLock) {
                                for (int i = mRoots.size() - 1; i >= 0; --i) {
                                    mRoots.get(i).loadSystemProperties();
                                }
                            }
                        }
                    };
                    SystemProperties.addChangeCallback(mSystemPropertyUpdater);
                }
    
                int index = findViewLocked(view, false);
                if (index >= 0) {
                    if (mDyingViews.contains(view)) {
                        // Don't wait for MSG_DIE to make it's way through root's queue.
                        mRoots.get(index).doDie();
                    } else {
                        throw new IllegalStateException("View " + view
                                + " has already been added to the window manager.");
                    }
                    // The previous removeView() had not completed executing. Now it has.
                }
    
                // If this is a panel window, then find the window it is being
                // attached to for future reference.
                if (wparams.type >= WindowManager.LayoutParams.FIRST_SUB_WINDOW &&
                        wparams.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) {
                    final int count = mViews.size();
                    for (int i = 0; i < count; i++) {
                        if (mRoots.get(i).mWindow.asBinder() == wparams.token) {
                            panelParentView = mViews.get(i);
                        }
                    }
                }
    
                root = new ViewRootImpl(view.getContext(), display);//重要
    
                view.setLayoutParams(wparams);
    
                mViews.add(view);
                mRoots.add(root);
                mParams.add(wparams);
            }
    

    可以看到ViewRootImpl 又调用了addView。查看ViewRootImpl的源代码发现。

    2.5ViewRootImpl 构造方法

    Paste_Image.png

    根据mThread,进一步查找到

    void checkThread() {
            if (mThread != Thread.currentThread()) {
                throw new CalledFromWrongThreadException(
                        "Only the original thread that created a view hierarchy can touch its views.");
            }
        }
    

    查到这步我们就可以知道了:setContentView是在主线程中进行的,其ViewRootImpl指向主线程。 在子线程操作View。Thread.currentThread()不再是UI线程。故而不想等,报错。

    相关文章

      网友评论

        本文标题:android 为什么只能在主线程更新View

        本文链接:https://www.haomeiwen.com/subject/mmowhxtx.html