正文
由UI刷新谈到线程安全和Android单线程模型
小程序:扫一扫查出行
【扫一扫了解最新限行尾号】
复制小程序
【扫一扫了解最新限行尾号】
复制小程序
1、为什么说invalidate()不能直接在线程中调用?
Android提供了Invalidate方法实现界面刷新,但是Invalidate不能直接在非UI主线程中调用, 因为他是违背了单线程模型 :Android UI操作并不是线程安全的,并且这些操作必须在UI线程中调用。例如:在非UI线程中调用invalidate会导致线程不安全,也就是说可能在非UI线程中刷新界面的时候,UI线程(或者其他非UI线程)也在刷新界面,这样就导致多个界面刷新的操作不能同步,导致线程不安全
2、它是怎么违背单线程的?
一个 Android 程序开始运行时,就有一个主线程Main Thread被创建。该线程主要负责UI界面的显示、更新和控件交互,所以又叫UI Thread。由于 只有UI线程更新界面 所以说Android是单线程模型。
一个Android程序创建之初,一个Process呈现的是单线程模型--即Main Thread,在非主线程(UI线程)外调invalidate()刷新界面出现异常,即是说用其他的线程更新UI,android中是不被允许的。
3、android ui为什么说不是线程安全的?
UI线程 存在不安全的操作 :android UI 中提供invalidate()来更新界面,而invalidate()方法是线程不安全。
4、android ui操作为什么一定要在UI线程中执行?
UI主线程是更新UI界面的, 更新了界面才能看到运行的效果 。
再者Android UI操作并不是线程安全的并且这些操作必须在UI线程中执行。如果在子线程中直接修改UI,会导致异常。
5、UI线程及Android的单线程模型原则
5.1 main thread
当应用启动,系统会创建一个主线程(main thread)。
这个主线程负责向UI组件分发事件(包括绘制事件),也是在这个主线程里,你的应用和Android的UI组件(components from the Android UI toolkit (components from the android.widget and android.view packages))发生交互。
所以main thread也叫UI thread也即UI线程。
5.2 UI thread
系统不会为每个组件单独创建线程,在同一个进程里的UI组件都会在UI线程里实例化,系统对每一个组件的调用都从UI线程分发出去。
结果就是,响应系统回调的方法(比如响应用户动作的onKeyDown()和各种生命周期回调)永远都是在UI线程里运行。
5.3 耗时任务
当App做一些比较重(intensive)的工作的时候,除非你合理地实现,否则单线程模型的performance会很poor。
特别的是,如果所有的工作都在UI线程,做一些比较耗时的工作比如访问网络或者数据库查询,都会阻塞UI线程,导致事件停止分发(包括绘制事件)。对于用户来说,应用看起来像是卡住了,更坏的情况是,如果UI线程blocked的时间太长(大约超过5秒),用户就会看到ANR(application not responding)的对话框。
5.4 Android单线程模型两原则
另外,Andoid UI toolkit并不是线程安全的,所以你不能从非UI线程来操纵UI组件。你必须把所有的UI操作放在UI线程里,所以Android的单线程模型有两条原则:
1.不要阻塞UI线程。
2.不要在UI线程之外访问Android UI toolkit(主要是这两个包中的组件:
android.widget
and android.view)。
5.5 由一个例子展开线程间通信问题http://blog.csdn.net/lvxiangan/article/details/39504145
6、invalidate()/postInvalidate()
Android程序中可以使用的界面刷新方法有两种,分别是利用invalidate和利用postInvalidate()来实现在线程中刷新界面。
Android中实现view的更新有两组方法,一组是invalidate,另一组是postInvalidate,其中前者是在UI线程自身中使用,而后者在非UI线程中使用。
Android提供了Invalidate方法实现界面刷新,但是Invalidate不能直接在线程中调用,因为他是违背了单线程模型:Android UI操作并不是线程安全的,并且这些操作必须在UI线程中调用。
6.1 特点
只要是view的子类,都会从view中继承invalidate和postInvalidate这两个方法。
当invalidate方法被调用的时候,就是在告诉系统,当前的view发生改变,应该尽可能快的来进行重绘。
这个方法仅能在UI线程中被调用。如果想要在工作线程中进行刷新界面,那么其他的方法将会被调用,这个方法就是postInvalidate方法。这个方法将会发送消息到主线程,当主线程的消息队列轮询到当前消息的时候,这个方法会被调用。
但是需要注意的是,刷新界面并不能保证马上刷新。只是尽可能快的进行刷新。尤其是在postInvalidate方法中,这种情况会出现。
7、小结
- 界面刷新的存在: UI界面要看想到运行效果,必定存在界面刷新这一需求
- UI线程不安全: 要刷新就得调用invalidate(),所以UI线程是线程不安全的
- 界面刷新的运行: 谈到刷新,就得明确这一动作只能在UI线程进行,多线程各自刷新是不可想象的
- 单线程模型: 由3可得Android是单线程模型这一观点,相应的也就存在着Android单线程模型两原则
- postInvalidate(): postInvalidate()只是将刷新消息发送到主线程,至于是否刷新、何时刷新得看主线程的运行
http://www.android100.org/html/201406/06/20132.html