Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
767 views
in Technique[技术] by (71.8m points)

android - No error "Only the original thread that created a view hierarchy can touch its views" when the view is updated without delay

I was faced with an interesting problem. If you write the following code in the onCreate/onStart/onResume method of activity:

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();
    }
});

or:

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();

how it should be, an error is thrown

android.view.ViewRoot $ CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views."

It is clear that in this case I must update the view in ui-thread (Handler, AsyncTask, runOnUiThread, view.post).

But if you update the view in another thread without delay (without sleep calling or without starting the thread by pressing a button), exception will not be thrown.

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();

Can anybody tell me why there is such a behavior?

UPDATE:

I have learned the source code of Android and came to the following conclusions. Nandeesh wrote the truth. When initializing the view called dispatchAttachedToWindow (AttachInfo info, int visibility) method of View, which initializes the mAttachInfo field. mAttachInfo object has mViewRootImpl field. If it is null, getViewRootImpl will returned as null:

public ViewRootImpl getViewRootImpl() {
        if (mAttachInfo != null) {
            return mAttachInfo.mViewRootImpl;
        }
        return null;
    }

ViewRootImpl contains checkThread method. It compares threads: the thread that created the view and thread of the request for the view update.

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

Thus, if the view was not initialized, there is no check and change do not throws exceptions.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

The check for thread is present only if textView relayout is done. But the Layouting of the view is only done after OnCreate is called . So till the Ui is not shown, changing of textView will not result in invalidating of the view.

But once the textView has been shown, the UI relayout is required, in which case the thread is checked. So you get the exception only after some time of Oncreate but not immediately.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...