android之handler使用与原理

下面的是个人对handler的一些感想,忘能帮助初学者
handler是什么
handler是android系统提供的一套消息机制的上层接口,使用handler可以轻松地切换任务线程那它可以用来干嘛呢。
当需要在子线程中进行耗时的I/O操作的时候,当耗时任务完成以后,需要在UI上做一些改变,但是在子线程不能访问handler这时就要使用handler。要记住一点,handler不是专门用来更新UI的。
接下来介绍几个概念。
MessageQueue
它是用来存储消息的,注意它是单链表的数据结构。
Looper
消息循环者,用来取MessageQueue的消息并处理,没消息阻塞。
好了,接下来慢慢介绍。
不知大家注意到了没子线程访问UI会报异常,这是因为不能再子线程更新UI,那么android是怎么确定的呢,因为ViewRootImpl会对UI操作进行验证,是由ViewRootImpl的checkThread来完成的。因此大家也别想着用什么办法绕过了,因为系统已经强制规定了。
Handler在创建的时候会用当前线程的Looper来构建消息循环系统,因此在子线程中直接使用Handler会报错,因为子线程是没有Looper的,那UI线程有没有呢,UI线程会在ActivityThread创建UI线程的时候初始化一个Looper,这也是主线程可以使用handler的原因,要在子线程使用handler,要先出初始化Looper,调用Looper.perpar()即可当调用handler的send方法时,它会调用MessageQueue的enqueueMessage()方法将消息放到队列中去,Looper发现有新消息时会处理消息,最终消息中的Runnable或者handler的handleMessage会调用。
这里要知道Looper是存储在ThreadLocal中的,它是一个作用域为当前线程的存储类。底下是个例子

 public class TestHandlerActivity extends AppCompatActivity {


        private static final String TAG = "TestHandlerActivity";

        private Handler mHandler = new Handler(){
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
                //获得刚才发送的Message对象,然后在这里进行UI操作
                Log.e(TAG,"------------> msg.what = " + msg.what);
            }
        };


        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_handler_test);
            initData();
        }

        private void initData() {

            //开启一个线程模拟处理耗时的操作
            new Thread(new Runnable() {
                @Override
                public void run() {

                    SystemClock.sleep(2000);
                    //通过Handler发送一个消息切换回主线程(mHandler所在的线程)
                    mHandler.sendEmptyMessage(0);
                }
            }).start();

        }   

这是一个很简单的例子,接下来再看用post方法发送已个Runnable接口的方法。

public class MainActivity extends Activity {

    private TextView text_view = null;
    private Button start = null;
    private Button end = null;

    //使用handler时首先要创建一个handler
    Handler handler = new Handler();
    //要用handler来处理多线程可以使用runnable接口,这里先定义该接口
    //线程中运行该接口的run函数
    Runnable update_thread = new Runnable()
    {
        public void run()
        {
            //线程每次执行时输出"UpdateThread..."文字,且自动换行
            //textview的append功能和Qt中的append类似,不会覆盖前面
            //的内容,只是Qt中的append默认是自动换行模式
            text_view.append("\nUpdateThread...");
            //延时1s后又将线程加入到线程队列中
            handler.postDelayed(update_thread, 1000);

        }
    };

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        text_view = (TextView)findViewById(R.id.text_view);
        start = (Button)findViewById(R.id.start);
        start.setOnClickListener(new StartClickListener());
        end = (Button)findViewById(R.id.end);
        end.setOnClickListener(new EndClickListener());

    }

    private class StartClickListener implements OnClickListener
    {
        public void onClick(View v) {
            // TODO Auto-generated method stub
            //将线程接口立刻送到线程队列中
            handler.post(update_thread);
        }                
    }

    private class EndClickListener implements OnClickListener
    {

        public void onClick(View v) {
            // TODO Auto-generated method stub
            //将接口从线程队列中移除
            handler.removeCallbacks(update_thread);
        }

    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.activity_main, menu);
        return true;
    }
}

接下来各自分析一下
MessageQueue
它主要用来存储消息,有两个基本操作,插入和读取,读取操作会伴随着删除操作,当Handler发送一条消息时会调用他的enqueueMessage方法插入消息,此时有了一条消息,接着它会调用自身的next方法读取消息并从队列中(数据结构是单链表)删除消息,接着Looper发现有消息就会把它交给handler去处理,handler调用自身的handlermessage()方法,这里要注意我们可以通过getMainLooper()得到UI现成的Looper,当在子线程创建Looper不用的时候要调用他的quitsafely()方法,否则Looper会一直阻塞。
好了,这就是消息处理机制了。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值