Android 中的线程机制之 Handler
题外话:一直以来学习的时候,都没有写笔记的习惯,前些日子随手写了之后,发现对一些东西理解的更深刻~ 这里就开始写小笔记吧,如果哪里错了,请各位帮忙指正,谢谢
android是单线程模型,所以在多线程的时候,并不能像java一样直接使用new Thread().start();
一.android 线程机制中Handler系列需要理解5个概念:
1.Message: 消息对象,Message Queue中的存放的对象。一个Message Queue中包含多个Message。
Message实例对象通常使用Message类里的静态方法obtain()---该方法有多个重载版本可供选择---通过该方法的创建并不一定是直接创建一个新的实例,而是先从Message Pool(消息池)中看有没有可用的Message实例,存在则直接取出返回这个实例。如果Message Pool中没有可用的Message实例,则才用给定的参数创建一个Message对象。
而调用removeMessages()时,将Message从Message Queue中删除,同时放入到Message Pool中。也可以通过Handler对象的obtainMessage()获取一个Message实例。
在Activity的onStop()或者onDestroy()使用Handler的方法removeMessages(int what) 配合removeCallbacks(Runnable r) 或直接使用mHandler.removeCallbacksAndMessages(null);可以避免内存泄露
2.Handler: 它直接继承自Object,一个Handler允许发送和处理Message或者Runnable对象,并且会关联到主线程的 MessageQueue 中。每个Handler具有一个单独的线程,并且关联到一个消息队列的线程,就是说一个Handler有一个固有的消息队列。当实例化一个Handler 的时候,它就承载在一个线程和消息队列的线程,这个Handler可以把Message或Runnable压入到消息队列,并且从消息队列中取出 Message或Runnable,进而操作它们。
Handler主要有两个作用:
- 在工作线程中发送消息。
- 在UI线程中获取、处理消息。
上面介绍到Handler可以把一个Message对象或者Runnable对象压入到消息队列中,进而在UI线程中获取Message或者执行Runnable对象,所以Handler把压入消息队列有两大体系,Post和sendMessage:
- Post:Post允许把一个Runnable对象入队到消息队列中。它的方法有:post(Runnable)、postAtTime(Runnable,long)、postDelayed(Runnable,long)。
- sendMessage:sendMessage允许把一个包含消息数据的Message对象压入到消息队列中。它的方法 有:sendEmptyMessage(int)、sendMessage(Message)、 sendMessageAtTime(Message,long)、sendMessageDelayed(Message,long)。
从上面的各种方法可以看出,不管是post还是sendMessage都具有多种方法,它们可以设定Runnable对象和Message对象被入队到消息队列中,是立即执行还是延迟执行。
3.MessageQueue:是一种数据结构,见名知义,就是一个消息队列,存放消息的地方。每一个线程最多只可以拥有一个MessageQueue数据结构。
创建一个线程的时候,并不会自动创建其MessageQueue。通常使用一个Looper对象对该线程的MessageQueue进行管理。主线程创建时,会创建一
个默认的Looper对象,而Looper对象的创建,将自动创建一个Message Queue。其他非主线程,不会自动创建Looper,要需要的时候,通过调
用prepare函数来实现。
4.Looper:是MessageQueue的管理者。每一个MessageQueue都不能脱离Looper而存在,Looper对象的创建是通过prepare函数来实现的。同时每一个Looper对象
和一个线程关联。通过调用Looper.myLooper()可以获得当前线程的Looper对象
创建一个Looper对象时,会同时创建一个MessageQueue对象。除了主线程有默认的Looper,其他线程默认是没有MessageQueue对象的,所以,不能
接受Message。如需要接受,自己定义一个Looper对象(通过prepare函数),这样该线程就有了自己的Looper对象和MessageQueue数据结构了。
Looper从MessageQueue中取出Message然后,交由Handler的handleMessage进行处理。处理完成后,调用Message.recycle()将其放入Message Pool中。
**5.HandlerThread:**这个类继承Thread类, 在类内部创建了Looper 变量,整体上实现的是通过Looper达到分发消息的作用。
Activity、Looper、Handler的关系如下图所示:
Android系统的消息队列和消息循环都是针对具体线程的,一个线程可以存在(当然也可以不存在)一个消息队列和一个消息循环(Looper),特定线程的消息只能分发给本线程,不能进行跨线程,跨进程通讯。但是创建的工作线程默认是没有消息循环和消息队列的,如果想让该线程具有消息队列和消息循环,需要在线程中首先调用Looper.prepare()来创建消息队列,然后调用Looper.loop()进入消息循环。
二. 示例Handler的用法 使用Handler对象的sendEmptyMessage或sendMessage方法来传递一个Bundle对象到Handler处理器。对于Handler类提供了重写方法handleMessage(Message msg) 来判断,通过msg.what来区分每条信息。
12345678910 | Handler myHandler = new``Handler() { public void handleMessage(Message msg) { switch``(msg.what) { case``TestHandler.GUIUPDATEIDENTIFIER: myBounceView.invalidate(); break``; } super``.handleMessage(msg); } }; |
---|
12345678910111213141516 | class myThread implements Runnable { public void run() { while``(!Thread.currentThread().isInterrupted()) { Message message = new``Message(); message.what = TestHandler.GUIUPDATEIDENTIFIER; TestHandler.``this``.myHandler.sendMessage(message); try``{ Thread.sleep(100); } catch``(InterruptedException e) { Thread.currentThread().interrupt(); } } } } |
---|