Why can update the UI in the child thread by setText

Why can update the UI in the child thread by setText

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

Under normal circumstances in the child thread will update the UI is being given, because it will be checked by checkThread in ViewRootImpl in, when ViewRootImpl not create is not checked, but here is mainly to have been created ViewRootImpl can also update the UI for analysis .

We look at the code and run directly through the results of sub-thread setText not being given.

public class MainActivity extends AppCompatActivity implements View.OnClickListener  {

    TextView text;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        text= findViewById(R.id.text); 
       }
    @Override
    public void onClick(View v) {
       new Thread((Runnable)()->{
           text.setText("改变后");
       }).start();
    }
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity"
    android:orientation="vertical">

    <TextView
        android:id="@+id/text"
        android:layout_width="100dp"
        android:layout_height="100dp"
        android:background="@color/colorAccent"
        android:text="改变前"
        />

    <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Button"
        android:onClick="onClick"
        />

</LinearLayout>

Change beforeHere Insert Picture Description
We can see after clicking on a smooth updated UI. The key point is that the android: layout_width = "100dp" android : layout_height = "100dp"
I am here to view size was fixed. Error certainly triggered checkThread, but they do not trigger can successfully updated UI, and setText not, in any case will trigger checkThread of.

In the setText method calls checkForRelayout, and this method will show the reason does not trigger the checkThread. checkThread is only carried out in requestLayout, all here, we do not call requestLayout will not be checkThread.

By following source code you will find that not all cases will be called requestLayout. In return there are two useless calls requestLayout, so we can not know the size of just View wrap_content, but match_parent or fixed dp, it will not trigger requestLayout, naturally, can be updated in the child thread.

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 ((mLayoutParams.width != LayoutParams.WRAP_CONTENT
                || (mMaxWidthMode == mMinWidthMode && mMaxWidth == mMinWidth))
                && (mHint == null || mHintLayout != null)
                && (mRight - mLeft - getCompoundPaddingLeft() - getCompoundPaddingRight() > 0)) {
            // Static width, so try making a new text layout.

            int oldht = mLayout.getHeight();
            int want = mLayout.getWidth();
            int hintWant = mHintLayout == null ? 0 : mHintLayout.getWidth();

            /*
             * No need to bring the text into view, since the size is not
             * changing (unless we do the requestLayout(), in which case it
             * will happen at measure).
             */
            makeNewLayout(want, hintWant, UNKNOWN_BORING, UNKNOWN_BORING,
                          mRight - mLeft - getCompoundPaddingLeft() - getCompoundPaddingRight(),
                          false);

            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();
            invalidate();
        } else {
            // Dynamic width, so we have no choice but to request a new
            // view layout with a new text layout.
            nullLayouts();
            requestLayout();
            invalidate();
        }
    }

Summary:
1. Call requestLayout is because the content requires a new view layout, when without the need will not call.
2. In the sub-thread UI updates through checkThread update to prevent child thread.
3. Call requestLayout only when View update trigger CheckThred, you do not call requestLayout means can be updated in the child thread.

Published an original article · won praise 0 · Views 65

Guess you like

Origin blog.csdn.net/m0_46496806/article/details/105356056