Android学习笔记040之Handler
- 格式:doc
- 大小:105.00 KB
- 文档页数:12
Android学习笔记040之Handler Android开发中我们常常会用到多线程,但是进行UI界面的更新只能在UI线程,而请求网络获取数据不能在UI线程,这就涉及到了线程之间的通信问题,Android系统给我提供了一个线程间通信的解决办法–Handler,下面我们来介绍一下Handler:1、Handler简介Handler是Android操作系统提供的线程通信工具,它主要有两个作用:将消息或者Runnable在主线程中的某个地方执行;安排一个动作在另外一个线程中执行。
每一个Handler 对象都会维护两个队列:消息队列和Runnable队列,都是由Android操作系统提供。
Handler 可以通过消息队列来发送、接收、处理消息;通过Runnable队列来启动、结束、休眠线程。
也就是说,Handler可以很方便的实现线程之间的通信。
2、Handler机制Handler机制产生的原因:一个APP启动之后就会自动创建一个UI线程来管理UI控件和处理对事件的分发,当界面上的一个控件,比如Button响应了点击事件之后,我们需要进行长时间的耗时操作,比如联网获取数据,但是Android的机制是在UI线程中5秒内没有响应就会ANR异常,所以我们需要将耗时操作放在子线程中处理,子线程处理完成之后去更新UI线程的界面,但是,我们知道UI线程是不安全的,所以子线程不能直接更新UI 线程中的界面,所以Android系统提供了Handler机制来解决这个问题。
Handler运行在UI线程,它通过接受子线程传递过来的Message更新UI线程的控件。
有几个核心类:Message、Looper、Handler、MessageQueue,下面我们来学习一下这几个核心类:2.1、MessageMessage消息类,主要实现对消息的封装和指定对消息的操作形式。
Message定义的变量和方法有:public int what:变量,用于定义此Message属于何种操作public Object obj:变量,用于定义此Message传递的信息数据,通过它传递信息public int arg1:变量,传递一些整型数据时使用public int arg2:变量,传递一些整型数据时使用常用的方法:copyFrom(Message o):复制一个消息getCallback():获取当前消息执行时的回调对象getData():获取在Message中传递的Bundle对象getTarget():获取到处理当前消息的Handler对象getWhen():获取到处理当前消息的时间,单位是毫秒obtain(Handler h, int what, int arg1, int arg2, Object obj):获取到Message对象,重载方法有:obtain(Handler h, int what, Object obj)、obtain(Handler h, int what)、obtain(Handler h)、obtain(Handler h, Runnable callback)、obtain()、obtain(Handler h, int what, int arg1, int arg2)、obtain(Message orig)setData(Bundle data):传递一个Bundle对象setTarget(Handler target):对应getTarget()recycle():将一个Message对象释放到消息池中常用的Message的方法和变量就是这些了,不过使用的时候也是有一些注意事项的:Message可以直接New出来,但是尽量使用obtain()方法从消息池中获取,节省资源如果只是需要携带简单的int类型消息,推荐使用Message.arg1和Message.arg2,比Bundle 节省内存用Message.what来标志不同的消息,以便处理,关于Message就简单介绍到这里,2.2、LooperLooper消息管道,Handler处理Message需要一个管道,Looper只有两个方法:prepare()和loop(),其中prepare()是初始化的方法。
在Android的Activity中,系统帮我们启动了一个Looper对象,但是在我们自定义的类中,需要我们自己去启动一个Looper对象,只需要实现下面的代码,就可以将一个普通的线程变成Looper线程:class LooperThread extends Thread {public Handler mHandler;public void run() {//将当前线程初始化为Looper线程Looper.prepare();......//循环处理消息Looper.loop();}}Looper是循环者的意思,Looper通过调用prepare()方法进行初始化,我们来分析一下prepare()方法:public class Looper {// 每个线程中的Looper对象其实是一个ThreadLocal,即线程本地存储(TLS)对象private static final ThreadLocal sThreadLocal = new ThreadLocal();// Looper内的消息队列final MessageQueue mQueue;// 当前线程Thread mThread;//其他属性// 每个Looper对象中有它的消息队列,和它所属的线程private Looper() {mQueue = new MessageQueue();mRun = true;mThread = Thread.currentThread();}// 我们调用该方法会在调用线程的TLS中创建Looper对象public static final void prepare() {if (sThreadLocal.get() != null) {// 试图在有Looper的线程中再次创建Looper将抛出异常throw new RuntimeException("Only one Looper may be created per thread");}sThreadLocal.set(new Looper());}// 其他方法}Looper内部维护着一个MessageQueue对象,每一个Thread中只能有一个Looper对象。
prepare()方法的核心功能就是将Looper对象定义为ThreadLocal,调用了loop()方法,Looper才真正开始工作,loop()不断的从自己的MessageQueue中取出任务执行,我们看一下loop方法代码:public static final void loop() {Looper me = myLooper(); //得到当前线程LooperMessageQueue queue = me.mQueue; //得到当前looper的MQBinder.clearCallingIdentity();final long ident = Binder.clearCallingIdentity();// 开始循环while (true) {Message msg = queue.next(); // 取出messageif (msg != null) {if (msg.target == null) {// message没有target为结束信号,退出循环return;}// 日志。
if (me.mLogging!= null) me.mLogging.println(">>>>> Dispatching to " + msg.target + " "+ msg.callback + ": " + msg.what);// 非常重要!将真正的处理工作交给message的target,即后面要讲的handlermsg.target.dispatchMessage(msg);// 还是日志。
if (me.mLogging!= null) me.mLogging.println("<<<<< Finished to " + msg.target + " "+ msg.callback);// 下面没看懂,同样不影响理解final long newIdent = Binder.clearCallingIdentity();if (ident != Ident) {Log.wtf("Looper", "Thread identity changed from 0x"+ Long.toHexString(ident) + " to 0x"+ Long.toHexString(newIdent) + " while dispatching to "+ msg.target.getClass().getName() + " "+ msg.callback + " what=" + msg.what);}// 回收message资源msg.recycle();}}}除了prepare()和loop()方法之外,Looper还提供了一些其他的方法:myLooper():获取当前线程Looper对象getThread():获取到当前Looper所属的线程quit():退出Looper的循环最后我们总结一下Looper:每一个线程只能有一个Looper对象,而且Looper是一个ThreadLocalLooper中维护着一个MessageQueue,loop()方法不断地从MessageQueue中取出任务执行普通的线程可以通过Looper变成一个Looper线程2.3、HandlerHandler消息处理类,Handler主要是往MessageQueue中添加消息和处理消息,但是只处理自己添加的消息。
即是:通知MessageQueue它要执行一个任务,在取到自己的时候执行那个任务,这个过程是异步的。
这里我们需要了解一下同步和异步的概念,举一个简单的例子:张三跟李四打电话,张三想要再跟王五通话,那么就必须要等到跟李四结束通话才可以。
这个就是同步通信,就是发送一个请求,等待这个请求完成返回结果才会继续处理下面的通信。