没有错误“只有创建视图层次结构的原始线程可以触摸其视图"当视图更新时没有延迟 [英] No error "Only the original thread that created a view hierarchy can touch its views" when the view is updated without delay

查看:22
本文介绍了没有错误“只有创建视图层次结构的原始线程可以触摸其视图"当视图更新时没有延迟的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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

或:

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

应该怎么办,报错了

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

很明显,在这种情况下我必须更新 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?

更新:

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

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 包含 checkThread 方法.它比较线程:创建视图的线程和请求视图更新的线程.

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.

推荐答案

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

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.

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

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.

这篇关于没有错误“只有创建视图层次结构的原始线程可以触摸其视图"当视图更新时没有延迟的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆