为什么要用消息处理机制
如果有多个线程更新UI,并且没有枷锁处理,会导致界面更新的错乱,而如果每个更新操作都进行枷锁处理,就会造成性能的下降,所以在Android开发中,为了使UI操作的线程是安全的,只允许主线程即UI线程可以更新UI组件。
我在平常开发中就会遇到多个线程并发操作UI组件的需求,Android提供了一条消息传递于处理机制来解决这个问题
如何通信
首先Handler作为任务执行者,一般创建在主线程,当子线程有需要发送的数据,通过创建Message对象,使用handler对象将消息发送到message Queue,message queue遵循了队列先进先出的原则,当主线程Looper循环消息的时候,会按照message queue队列的顺序放入消息,并将消息给到任务执行者handler去执行任务
通信原理
Handler创建完成后,内部的Looper以及MessageQueue就可以和handler一起协同工作,然后通过Handler的post方法将一个Runnable投递到handler内部的Looper中处理,也可以通过handler的send方法发送一个消息,这个消息会在Looper中处理,当handler的send方法被调用时,他会调用message Queue的enqueueMessage方法将这个消息放入消息队列中,然后Looper发现有新消息时,就会处理这个消息,最终消息中的Runnable或者handler的handler Message方法就会被调用。Looper运行在Handler所有线程,所以就把业务逻辑切换到主线程了、
Handler延迟消息
Looper
Looper是消息循环器,是消息处理机制的核心,它可以将一个普通的线程转换为一个Looper线程。线程不断循环的从Message Queue中获取Message,交给相信的Handler处理任务。
为什么Looper死循环不阻塞主线程?
因为主线程本来就是跑在一个这样的循环里,主线程本身就是一个死循环,当这个死循环停止,app也就退出了。 所以只要创建了其他的新线程处理事务,主线程的循环就不会导致系统卡死。
- 何时创建了其他的新线程运转?
- 是运行在主线程的ActivityThread的main()方法中创建了新的Binder线程,一些Activity生命周期就是通过这个机制在循环外执行起来的,方法处理完后,主线程继续循环下去
- 主线程的循环会不会消耗大量的CPU资源?
- 在主线程的Message Queue没有消息是,便阻塞在MessageQueue.next()中的native Poll Once()方法里,此时主线程会释放CPU资源进入休眠状态,直到下个消息到达或者有事务发生,所以主线程大多数时候是处于休眠状态,并不会消耗大量CPU资源
主线程向子线程发送消息
首先handler肯定是要创建到子线程当中,用于接收主线程发来消息进行处理,但是,因为子线程没有looper对象,首先需要调用looper.prepare(),当主线程发来消息后,已经准备好的looper同样会去消息队列当中循环消息,交给handler,但handler真正能够使用该数据还得调用looper.loop();
AsyncTask异步加载
Android UI线程阻塞5秒会引发ANR。
- AsyncTask后台运行有五个状态
准备状态:onPreExecute(),该方法将在执行后台好事操作前被调用。平常用于完成一些初始化的准备工作。
正在进行:doInBackground ()重写该方法就是在后台线程将要完成的任务,其结果必须由该函数返回并被传递到onPostExecute()中
进度更新:OnProgressUpdate该函数由UI线程在publishProgress()调用完成后被调用。
完成后台任务:onPostExecute()当后台任务完成后调用,并将dolnBackground()方法的返回值传给该方法
取消任务:onCancelled()再调用AsyncTask的cancel()方法是调用