没有错误"只有创建视图层次结构的原始线程才能触及其视图",无视延迟更新视图

Vla*_*kiy 8 multithreading android view ui-thread

我遇到了一个有趣的问题.如果您在onCreate/onStart/onResume活动方法中编写以下代码:

final Button myButton = (Button)findViewById(R.id.myButton);
final TextView myTextView = (TextView)findViewById(R.id.myTextView);
final Thread thread = new Thread(new Runnable() {
    @Override
    public void run() {
        myTextView.setText("Hello text");
    }
});
myButton.setOnClickListener(new OnClickListener() {
    @Override
        public void onClick(View v) {
        thread.start();
    }
});
Run Code Online (Sandbox Code Playgroud)

要么:

final TextView myTextView = (TextView)findViewById(R.id.myTextView);
final Thread thread = new Thread(new Runnable() {
    @Override
    public void run() {
        try {
            Thread.currentThread().sleep(500);
        }
        catch (InterruptedException e) {
            e.printStackTrace();
        }
        myTextView.setText("Hello text");
    }
});
thread.start();
Run Code Online (Sandbox Code Playgroud)

应该如何,抛出一个错误

android.view.ViewRoot $ CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views."
Run Code Online (Sandbox Code Playgroud)

很明显,在这种情况下,我必须在ui-thread中更新视图 (Handler, AsyncTask, runOnUiThread, view.post).

但是如果你在没有延迟的情况下更新另一个线程中的视图(没有睡眠调用或没有通过按下按钮启动线程),则不会抛出异常.

final TextView myTextView = (TextView)findViewById(R.id.myTextView);
final Thread thread = new Thread(new Runnable() {
    @Override
    public void run() {
        myTextView.setText("Hello text");
    }
});
thread.start();
Run Code Online (Sandbox Code Playgroud)

谁能告诉我为什么会有这样的行为?

更新:

我已经学习了Android的源代码并得出以下结论.南德斯写下了真相.初始化视图时,调用View的dispatchAttachedToWindow(AttachInfo info,int visibility)方法,初始化mAttachInfo字段.mAttachInfo对象具有mViewRootImpl字段.如果为null,则getViewRootImpl将返回null:

public ViewRootImpl getViewRootImpl() {
        if (mAttachInfo != null) {
            return mAttachInfo.mViewRootImpl;
        }
        return null;
    }
Run Code Online (Sandbox Code Playgroud)

ViewRootImpl包含checkThread方法.它比较线程:创建视图的线程和视图更新请求的线程.

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

因此,如果视图未初始化,则不会检查和更改不会抛出异常.

nan*_*esh 9

仅在textView重新布局完成时才会检查线程.但是视图的Layouting只有在OnCreate被调用之后才会完成.因此,直到Ui未显示,更改textView不会导致视图无效.

但是一旦显示了textView,就需要重新布局UI,在这种情况下会检查线程.因此,只有在Oncreate的一段时间后才能获得异常但不会立即获得异常.