Android为什么在非UI线程中进行UI操作而不报错

一般而言,android中相关的view和控件不是线程安全的,Android会禁止在非UI线程更新UI,对于显式的非法操作,比如说直接在Activity里创建子线程,然后直接在子线程中操作UI等,Android会直接异常退出,并提示should run on UIThread之类的错误日志信息。而对于隐式的非法操作,App不会直接简单粗暴地异常退出,只是出现奇怪的结果,Only the original thread that created a view hierarchy can touch its views便是一个例子,字面意思是只有创建视图层次结构的原始线程才能操作它的View。

但我们有时候会遇到:在非UI线程中运行UI操作而不报错

比如:

public class MainActivity extends AppCompatActivity {
    TextView textView;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        textView =(TextView)findViewById(R.id.textview);
        change_text();

    }

    public void change_text(){
        new Thread(){
            @Override
            public void run(){
                super.run();
                try {
                    textView.setText("改变文字信息");
                }
                catch (Exception E){
                    E.printStackTrace();
                }
            }
        }.start();
    }
}

这段代码把更新UI操作放在一个非UI线程中,按道理说会出错,接下来看看效果:

excuse me?居然成功了?

不要急,我们在try语句里面添加sleep(3000),让这个线程sleep3秒试试:

try {
                    sleep(3000);
                    textView.setText("改变文字信息");
                }

看看效果:

这次UI没有更新成功了,还是系统初始化的“Hello World”。

看看Android Monitor里面:

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

现在大家应该知道为什么刚刚能更新成功了吧,因为Main Thread(也就是UI Thread)一开始并没有初始化完成,等到3秒后,这时候Main Thread肯定已经初始化完成了,这个时候我们在其他线程中更新UI,是不行的,就会像上面一样

 Only the original thread that created a view hierarchy can touch its views.

正确的方法:(1)直接在Main Thread(也就是UI Thread)里面进行UI更新操作,这个不多说。

                      (2)或者利用handler进程间通信,把UI操作放进Main Thread,如下:

①.在主线程中创建handler,因为handler与创建handler所在的线程绑定

②.handleMessage(msg)方法里再处理UI更新,这个时候UI更新操作就会被放到UI线程里面去了;

public class MainActivity extends AppCompatActivity {
    TextView textView;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        textView =(TextView)findViewById(R.id.textview);
        change_text();
    }

    public void change_text(){
        new Thread(){
            @Override
            public void run(){
                super.run();
                try {
                    sleep(3000);
                }
                catch (Exception E){
                    E.printStackTrace();
                }
                Message mg=Message.obtain();
                mg.arg1=1;
                myHandler.sendMessage(mg);
            }
        }.start();
    }

    Handler myHandler = new Handler(){
        /**
         * handleMessage接收消息后进行相应的处理
         */
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            if(msg.arg1==1){
                //改变文字信息
                textView.setText("改变文字信息");
            }
        }
    };
}

 

反正就是UI 操作一定要放在UI进程里面就对了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值