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

【Android源码分析】 Android子线程可以更新UI,第1张

【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

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/5707379.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-17
下一篇 2022-12-17

发表评论

登录后才能评论

评论列表(0条)

保存