Android(7)消息通信

Android真的不能在子线程操作UI吗

很多很多很多很多。。。文章,书籍就会说一句,3.0之后将耗时操作必须放到子线程完成,主线程主要用来操作或者更新UI,但是我们深入分析其实一种极端情况是可以访问的。
看如下代码:

 protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main2);

        foot = (TextView) findViewById(R.id.dynamic_add);
        Log.d("Thread:", Thread.currentThread().getName());

        foot.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        Log.d("Thread:", Thread.currentThread().getName());
                        foot.setText("子线程1");

                    }
                }).start();
            }
        });

        Thread thread = new Thread(){
            @Override
            public void run() {
                Log.d("Thread:", Thread.currentThread().getName());
                foot.setText("子线程2");

            }
        };
        thread.start();
    }

如果什么
也不操作,text确实会变成“子线程2”,为什么呢?通过源码分析,对UI进行操作时是使用ViewRoot的checkThread方法检查当前线程,然而当我们创建Activ作创建,所以导致在子线程可以操UI。
这时如果我们点击一个TextView则会报错:

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

嗯。这才是我们要的结果。


Handler机制

handler是Android最常用的消息通信机制,其实真正的通信还要有MessageQueue(内部其实是个链表)和Looper,三者一起协作才是我们常用的Handler。
Looper使用LocalThread变量保存,此变量比较特殊作用域为线程。

  1. 当创建Handler时就会获取当前线程的Looper。

  2. 创建完成后,我们可以在任意线程使用Handler,当我们使用send或者post发送 信息的时候,消息会发送至创建handler的线程的MessageQueue中。

  3. Looper会不断循环查询MQ中是否有新的消息,如果有则进行处理,如果没有则等待。

    4.处理时首先查询是否有回调(post的参数Runnable),如果没有查询Handler是否有回调,如果为空,才交给handleMessage进行处理。

Handler handler = new Handler()
    {
        @Override
        public void handleMessage(Message msg) {
            Thread.currentThread().getName();
            foot.setText("子线程1");
        }
    };
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main2);

        foot = (TextView) findViewById(R.id.dynamic_add);
        foot.setText("主线程");

        Log.d("Thread:", Thread.currentThread().getName());
        foot.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        Thread.currentThread().getName();
                        Message message = new Message();
                        handler.sendMessage(message);

                    }
                }).start();
            }
        });

    }

当我们点击TextView时,TextView会变为子线程1。
记住一句话:Handler会将消息(Message)或者操作(Runnable)搬运至创建它的线程处理。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值