非UI线程调用textView.setText没有错误发生。为什么?

4
我编写了以下代码,基本上是从一个线程开始,在该线程中更改TextView的文本。 我原本预期会出现错误,因为我从另一个线程而不是主线程访问TextTiew(UI元素)。 但是它正常工作。据我所知,这不应该是可能的。 我不明白,我错过了什么?
public class MainActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        TextView tv = (TextView) findViewById(R.id.view1);
        tv.setText(Thread.currentThread().getName());

        Thread theThread = new Thread(new aRunnable(tv));
        theThread.start();      
    }
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.activity_main, menu);
        return true;
    }
}

public class ARunnable implements Runnable{     
    TextView tv;    
    public ARunnable(TextView tv){
        this.tv = tv;
    }   
    @Override
    public void run() {
        tv.setText(tv.getText()+"----" + Thread.currentThread().getName()); 
    }

}

我假设 aThread 确实是 ARunnable - njzk2
1
@Bob,如果你查看这个格式不良的代码片段,https://dev59.com/o2025IYBdhLWcg3wW0yx,你会发现他做了和你类似的事情,但是对他来说却崩溃了。这让我更加困惑。 - Simon Zettervall
我也是^^ 有人能运行我的代码测试一下是否会崩溃吗? 我在三星Note 10.1上运行它。 输出是main---Thread-1205。 - doschi
1
@Simon Bob 正如我在下面所指出的,Android并不一定始终执行此检查。尽管如此,即使跨线程UI调用不会抛出异常,这也是一个坏主意。文档(链接如下)清楚地说明UI类不是线程安全的。他们没有说明如果您做错了,Android将始终捕获您。不同版本的Android甚至-天佑-不同设备的实现更改可能已更改了哪些UI方法会抛出异常。 - j__m
@j__m 谢谢你的解释。我知道这不是它应该完成的方式。我想尝试一下处理程序,但是为什么没有崩溃让我感到困惑... - doschi
1个回答

2

根据文档,请勿在UI线程之外访问Android UI工具包。但文档并没有说明Android本身包含任何代码来阻止您这样做,这只是一个可能会产生意想不到的副作用的坏主意。

您应该调用Activity.runOnUiThread()以从其他线程更新UI。


实际上,如果您尝试在主线程之外修改视图,它将抛出异常。 - Simon Zettervall
当我试图在AsyncTask中访问一个ImageView时,出现了一个运行时错误,说我没有权限。我以为所有的UI元素都会发生这种情况。 - doschi
应该使用处理程序来设置文本。 - Nitesh Khosla
1
据我所知,只有内部类ViewRootImpl包含这样的检查。任何不涉及ViewRootImpl的UI代码都不会抛出异常,但仍然不是线程安全的。 - j__m
请查看j__m在问题中的评论。 - doschi

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接