Android中Handler、Looper、MessageQueue的工作原理

为了更好的理解Handler的工作原理,先介绍一下与Handler一起工作的几个组件。

  • Message: Handler接收和处理的消息对象

  • Looper:每个线程只能拥有一个Looper。它的loop方法负责读取MessageQueue中的消息,之后把消息交给发送该消息的Handler处理

  • MessageQueue:消息队列,使用先进先出的方式来管理Message。程序创建Looper对象时会在它的构造器中创建MessageQueue对象。下面是Looper的构造函数:

private Looper() {
    mQueue = new MessageQueue();//这里创建MessageQueue,这个Queue就负责管理消息
    mRun = true;
    mThread = Thread.currentThread();
}

  • Handler,它的作用有两个——发送消息和处理消息。程序使用Handler发送消息,被Handler发送的消息必须被送到指定的MessageQueue。也就是说,如果希望Handler正常工作,必须在当前线程中有一个MessageQueue,否则消息就没地方保存了。而MessageQueue是由Looper管理的,因此必须在当前线程中有一个Looper对象,可以分如下两种情况处理:

  1. 主UI线程中,系统已经初始化了一个Looper对象,因此程序直接创建Handler即可,然后就可以通过Handler来发送消息和处理消息了。

  2. 程序员自己启动的子线程中,必须自己创建一个Looper对象,并启动它。调用它的prepare()方法即可创建Looper对象。

prepare()方法保证每个线程最多只有一个Looper对象:

public static final void prepare() {
    if (sThreadLocal.get() != null) {
        throw new RuntimeException("Only one Looper may be created per thread");
    }
    sThreadLocal.set(new Looper());//这里创建Looper对象并放到ThreadLocal中
}

然后调用Looper的静态loop()方法来启动它。loop()方法使用一个死循环不断取出MessageQueue中的消息,并将其分发给对应的Handler进行处理:

for(;;) {
    Message msg = queue.next();//获取Queue中的下一个消息,如果没有,将会阻塞
    if (msg == null) {
        //如果消息为null,表明MessageQueue正在退出
        return;
    }
    ...
    msg.target.dispatchMessage(msg);
    ...
}


在线程中使用Handler的步骤如下:

  1. 调用Looper.prepare()为当前线程创建Looper对象,这将自动创建与之配套的MessageQueue

  2. 创建Handler子类的实例,重写handleMessage(Message msg)分发,该方法负责处理来自其他线程的消息

  3. 调用Looper.loop()启动Looper

例:输入一个整数,单击“计算”按钮,计算小于这个整数的所有质数。Activity的代码如下:

public class CalPrime extends Activity {
    static final String UPPER_NUM = "upper";
    EditText etNum;
    CalThread calThread;
    //定义一个线程类
    class CalThread extends Thread {
        public Handler mHandler;
        public void run() {
            Looper.prepare(); //Step1.创建Looper对象
            mHandler = new Handler() { //Step2.创建Handler对象
                //重写处理Message的方法
                @Override
                public void handleMessage(Message msg) {
                    if (msg.what == 123) {
                        int upper = msg.getData().getInt(UPPER_NUM);
                        List<Integer> nums = new ArrayList<Integer>();
                        outer:
                        for (int i = 2; i <= upper; i++) {
                            //用i % (从2开始到i的平方根的所有整数)
                            for (int j = 2; j <= Math.sqrt(i); j++) {
                                // 如果可以整除,则不是质数
                                if (i != 2 && i % j == 0) {
                                    continue outer;
                                }
                            }
                            nums.add(i);
                        }
                        Toast.makeText(CalPrime.this, nums.toString(), Toast.LENGTH_LONG).show();
                    }
                }
            };
            Looper.loop(); //Step3.启动Looper
        }
    }
    
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        etNum = (EditText)findViewById(R.id.etNum);
        calThread = new CalThread();
        calThread.start();
    }
    
    //为按钮提供处理函数
    public void cal(View source) {
        Message msg = new Message();
        msg.what = 0x123;
        Bundle bundle = new Bundle();
        bundle.putInt(UPPER_NUM, Integer.parseInt(etNum.getText().toString()));
        msg.setData(bundle);
        //向新线程中的Handler发送消息
        calThread.mHandler.sendMessage(msg);
    }
}

转载于:https://my.oschina.net/itblog/blog/401606

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值