栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

【Android源码分析】 Android子线程可以更新UI

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

【Android源码分析】 Android子线程可以更新UI

文章目录

一、现象:子线程更新UI操作,竟然不崩溃二、原因:宽和高尺寸未变化,仅需替换text

2.1 当TextView宽和高尺寸未变化,则子线程调用setText,不崩溃!2.2 当TextView宽和高尺寸发生了变化,则子线程调用setText,崩溃! 三、分析:

上文中有两处不会调用requestLayout,另有两处会调用requestLayout。因为:mParent被ViewRootImpl赋值所以:mParent.requestLayout()调用的是ViewRootImpl.requestLayout()子线程更新UI会崩溃就是因为checkThread中的CalledFromWrongThreadException

一、现象:子线程更新UI操作,竟然不崩溃
    private TextView textView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        textView = findViewById(R.id.tv);
        Button button = findViewById(R.id.btn);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                new Thread() {
                    @Override
                    public void run() {
                        super.run();
                        //子线程更新UI:setText未崩溃
                        textView.setText("test");
                    }
                }.start();
            }
        });
    } 
二、原因:宽和高尺寸未变化,仅需替换text 2.1 当TextView宽和高尺寸未变化,则子线程调用setText,不崩溃! 2.2 当TextView宽和高尺寸发生了变化,则子线程调用setText,崩溃!
    
    @UnsupportedAppUsage
    private void checkForRelayout() {
        // If we have a fixed width, we can just swap in a new text layout
        //如果固定了宽度,我们只需替换一个新的text layout。
        // if the text height stays the same or if the view height is fixed.
        //如果高度不变,或者固定了高度。
        
三、分析:
public class TextView extends View implements ...

    private void setText(CharSequence text, BufferType type,
                         boolean notifyBefore, int oldlen) {
        ...
        if (mLayout != null) {
            checkForRelayout();
        }
        ...
    }
public class TextView extends View implements ...

    
    @UnsupportedAppUsage
    private void checkForRelayout() {
        // If we have a fixed width, we can just swap in a new text layout
        // if the text height stays the same or if the view height is fixed.

        if (...) {
            // Static width, so try making a new text layout.
            ...
            
            if (mEllipsize != TextUtils.TruncateAt.MARQUEE) {
                // In a fixed-height view, so use our new text layout.
                if (mLayoutParams.height != LayoutParams.WRAP_ConTENT
                        && mLayoutParams.height != LayoutParams.MATCH_PARENT) {
                    autoSizeText();
                    invalidate();
                    return;
                }

                // Dynamic height, but height has stayed the same,
                // so use our new text layout.
                if (mLayout.getHeight() == oldht
                        && (mHintLayout == null || mHintLayout.getHeight() == oldht)) {
                    autoSizeText();
                    invalidate();
                    return;
                }
            }

            // We lose: the height has changed and we have a dynamic height.
            // Request a new view layout using our new text layout.
            requestLayout();//!!!这里才会checkThread
            invalidate();
        } else {
            // Dynamic width, so we have no choice but to request a new
            // view layout with a new text layout.
            nullLayouts();
            requestLayout();//!!!这里才会checkThread
            invalidate();
        }
    }
上文中有两处不会调用requestLayout, 另有两处会调用requestLayout。

只有需要新的view layout时,才需要调用requestLayout
(Request a new view layout using our new text layout.)

public class View implements ...

    public void requestLayout() {
        ...
        if (mParent != null && !mParent.isLayoutRequested()) {
            mParent.requestLayout();
        }
        ...
    }
因为:mParent被ViewRootImpl赋值
public class View implements ...

    void assignParent(ViewParent parent) {
        if (mParent == null) {
            mParent = parent;
        }
        ...
    }
public final class ViewRootImpl implements ViewParent, ...

    public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView,
            int userId) {
            ...
            view.assignParent(this);
            ...
    }
所以:mParent.requestLayout()调用的是ViewRootImpl.requestLayout()
public final class ViewRootImpl implements ViewParent, ...

    @Override
    public void requestLayout() {
        if (!mHandlingLayoutInLayoutRequest) {
            checkThread();
            mLayoutRequested = true;
            scheduleTraversals();
        }
    }

    void checkThread() {
        if (mThread != Thread.currentThread()) {
            throw new CalledFromWrongThreadException(
                    "only the original thread that created a view hierarchy can touch its views.");
        }
    }
子线程更新UI会崩溃就是因为checkThread中的CalledFromWrongThreadException
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/708836.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号