Android 中 Handler 机制

1,706 阅读4分钟

1.Handler概述

Handler 可以将一个任务切换到Handler所在线程中去执行,Handler的主要作用是更新UI,有时候需要在子线程进行耗时的I/O操作(读取文件或者访问网络),当耗时任务完成后,需要在UI线程中做一些改变,由于我们不能在子线程中访问UI控件,否则会发生异常,通过Handler就可以将跟新UI操作切换到主线程中执行。

2.Handler机制

这里写图片描述

注意:子线程中默认是没有Looper的,如果要使用Handler就必须为子线程创建Looper。如果当前线程没有Looper就会报错,Can’t create handler inside thread that has not called Looper.prepare()
主线程(UI线程)即是ActivityThread,ActivityThread被创建时会初始化Looper,所以在主线程中直接可以使用Handler。

  • Android消息机制主要是指Handler的运行机制及Handler所附带的MessageQueue和Looper的工作过程

  • Android中访问UI只能在主线程中进行,如果在子线程中访问UI,就会抛出异常,Handler解决了在子线程中无法访问UI的矛盾。
    系统为什么不容允许在子线程中访问UI?
    Android的UI控件不是线程安全的,在多线程中并发访问可能出现问题。

Handler的工作过程

这里写图片描述

Handler的send方法被调用时,它会调用MessageQueue的enqueueMessage方法,将消息放入消息队列中,当Looper发现有新消息来时,就会处理这个消息,最终Handler的handleMessage方法就会被调用

3.Android消息机制分析

(1)ThreadLocal的工作原理

ThreadLocal是一个线程内部的数据存储类,通过它可以在指定线程中存储数据,数据存储以后,只有在指定的线程中获取到存储数据,对于其他线程来说则无法获取到数据。

可能还是不太好理解,下面直接上代码
这里写图片描述

运行结果截图:
这里写图片描述

可以看出不同线程访问的是同一个ThreadLocal,但是它们通过ThreadLocal获取的值却不一样。
主线程设置的是true,所以获取到的是true
第一个子线程设置的是false,所以获取到的是false
第二个子线程没有设置,所以获取到的是null

(2)消息队列MessageQueue的工作原理

这里写图片描述

MessageQueue:消息队列,内部实现是通过一个单链表的数据结构来维护消息列表

eqeueMessage:就是向单链表中插入数据。
next:是一个无线循环的方法,如果没有消息,next方法就一直阻塞在这了
如果有消息,next方法就返回这条消息并将消息从单列表中移除。

(3)Looper的工作原理

Looper扮演者消息循环的角色,不停的从消息队列MessageQueue中查看是否具有消息,如果有消息就会立刻处理,否则就一直阻塞在那里

Handler中需要Looper,没有Looper线程就会报错,通过Looper.prepare()就可以为当前线程创建一个Looper,通过Looper.loop()来开启消息循环

下面以代码来演示,如果子线程中没有创建Looper就会报错,直接上代码:

package com.zhoujian.handler;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.util.Log;
import android.view.View;
import android.widget.Button;

public class MainActivity extends Activity
{
    private static final String TAG = "MainActivity";
    private Handler mHandler;

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

        Button bt_send = (Button) findViewById(R.id.bt_send);
        bt_send.setOnClickListener(new View.OnClickListener()
        {
            @Override
            public void onClick(View v)
            {
                Message msg = mHandler.obtainMessage();
                mHandler.sendMessage(msg);
            }
        });

        new Thread() 
        {
            @Override
            public void run() 
            {       
                mHandler = new Handler() 
                {
                    @Override
                    public void handleMessage(Message msg)
                    {
                        super.handleMessage(msg);
                        Log.i(TAG, "收到了主线程发来的消息");
                    }
                };
            }
        }.start();
    }
}

报错信息:
这里写图片描述

正确的代码:
这里写图片描述

4.最后来一个简单的Handler实例

直接上代码:

package com.zhoujian.handler;

import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;


public class MainActivity extends Activity
{
    private static final String TAG = "MainActivity";
    private static final int SEND_MESSAGE_FLAG = 1;
    private Button bt_send;
    private TextView tv_message;

    Handler mHandler = new Handler()
    {
        private Bundle mData;
        @Override
        public void handleMessage(Message msg)
        {
            super.handleMessage(msg);

            switch (msg.what)
            {
                case SEND_MESSAGE_FLAG:
                    mData = msg.getData();
                    String name = mData.getString("name");
                    String sex = mData.getString("sex");
                    tv_message.setText(msg.obj.toString());
                    //tv_message.setText(name+" :  "+sex);
                    break;
            }
        }
    };

    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initView();
        clickEvent();
    }

    private void clickEvent()
    {

        bt_send.setOnClickListener(new View.OnClickListener()
        {
            @Override
            public void onClick(View v) {
                new Thread()
                {
                    public void run()
                    {
                        // 在此执行耗时工作,执行完毕后调用handler发送消息
                        try
                        {
                            //睡眠1秒 模拟执行耗时任务
                            Thread.sleep(1000);
                            //发送消息
                            Message message= Message.obtain();
                            message.what=SEND_MESSAGE_FLAG;
                            Bundle mBundle = new Bundle();
                            mBundle.putString("name","周建");
                            mBundle.putString("sex","男");
                            message.setData(mBundle);
                            //mHandler.sendMessage(message);  
                            mHandler.obtainMessage(SEND_MESSAGE_FLAG,"消息来啦")                                                       .sendToTarget();
                        }
                        catch (Exception e)
                        {
                            e.printStackTrace();
                        }
                    }
                }.start();

            }
        });
    }

    private void initView()
    {
        bt_send = (Button) findViewById(R.id.bt_send);
        tv_message= (TextView) findViewById(R.id.tv_message);
    }
}

运行结果截图:

这里写图片描述

这里写图片描述