由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
由UI刷新谈到线程安全和Android单线程模型的更多相关文章
- 为什么说android UI操作不是线程安全的
转载于:http://blog.csdn.net/lvxiangan/article/details/17218409#t2 UI线程及Android的单线程模型原则 使用Worker线程 Commu ...
- Android开发 View的UI刷新Invalidate和postInvalidate
Invalidate 正常刷新 /** * 使整个视图无效.如果视图可见, * {@link #onDraw(android.graphics.Canvas)} 调用此方法后将在后续的UI刷新里调用o ...
- Android的UI设计与后台线程交互
本文将讨论Android应用程序的线程模型以及如何使用线程来处理耗时较长的操作,而不是在主线程中执行,保证用户界面(UI)的流畅运行.本文还将阐述一些用户界面(UI)中与线程交互的API.UI用户界面 ...
- Android开发UI之在子线程中更新UI
转自第一行代码-Android Android是不允许在子线程中进行UI操作的.在子线程中去执行耗时操作,然后根据任务的执行结果来更新相应的UI控件,需要用到Android提供的异步消息处理机制. 代 ...
- 转载【浅谈ThreadPool 线程池】
浅谈ThreadPool 线程池 http://www.cnblogs.com/xugang/archive/2010/04/20/1716042.html
- 浅谈Java线程安全
浅谈Java线程安全 - - 2019-04-25 17:37:28 线程安全 Java中的线程安全 按照线程安全的安全程序由强至弱来排序,我们可以将Java语言中各种操作共享的数据分为以下五类 ...
- 浅谈ThreadPool 线程池(引用)
出自:http://www.cnblogs.com/xugang/archive/2010/04/20/1716042.html 浅谈ThreadPool 线程池 相关概念: 线程池可以看做容纳线程的 ...
- 【转】浅谈Node.js单线程模型
Node.js采用 事件驱动 和 异步I/O 的方式,实现了一个单线程.高并发的运行时环境,而单线程就意味着同一时间只能做一件事,那么Node.js如何利用单线程来实现高并发和异步I/O?本文将围绕这 ...
- UI开发模式对比:JSP、Android、Flex
前一篇文章分析了Java平台下不同类型WEB框架对开发模式的影响,多数Java领域的WEB框架都是聚焦于服务端MVC的实现,这些框架对View的支持,通常是基于标准的JSP或类似JSP的模板技术如Fr ...
随机推荐
- java并发编程实战:第十一章----性能和可伸缩性
线程的最主要目的是提高程序的运行性能,但性能的提升会导致复杂性的提升,又会导致安全性和活跃性的风险 一.对性能的思考 提升性能意味着用更少的资源做更多地事情.要想通过并发来获得更好的性能,就要更有效地 ...
- An error "Host key verification failed" when you connect to other computer by OSX SSH
Here's quick way to remove all entries in the host file: In an OSX terminal, type rm -f ~/.ssh/known ...
- 更改JupyterNotebook默认文件路径 行之有效!
在安装了Anaconda以后浏览器默认打开的是C盘用户目录,平时不想把一些文件.代码放在C盘尤其是用户目录下,所以考虑将默认路径改掉,尝试了网上的几种方法,终于找到了一种可行有效的. 1.找到jupy ...
- 详解CSS float属性
CSS中的float属性是一个频繁用到的属性,对于初学者来说,如果没有理解好浮动的意义和表现出来的特性,在使用的使用很容易陷入困惑,云里雾里,搞不清楚状态.本文将从最基本的知识开始说起,谈谈关于浮动的 ...
- VR与AR的发展趋势分析
概要 你是否想象过与神秘的深海生物近距离接触?你是否梦想过穿戴钢铁侠那样的超先进科技装备成为超级英雄?你又是否幻想过与梦中的女神面对面的交流?这些可能在以前都只能是存在于脑海中的幻想,可是在如今有一项 ...
- 如何在TortoiseGit中使用ssh-keygen生成的key
再windows 用TortoiseGit 时,git clone 项目时 提示 "Couldn't load this key (OpenSSH SSH-2 private key),如下 ...
- 异步和等待(async和await)
在.Net 4.5中,通过async和await两个关键字,引入了一种新的基于任务的异步编程模型(TAP).在这种方式下,可以通过类似同步方式编写异步代码,极大简化了异步编程模型.如下式一个简单的实例 ...
- Sql Server中使用存储过程来实现一些时间差的改变
Sql Server中的时间差是使用DATEDIFF来是现的 语法如下:DATEDIFF(要显示时间格式,开始时间,结束时间) 比如:DATEDIFF(minute,'2019-2-28 8:30', ...
- Newtonsoft.Json Deserialize Type 或者 同类型 变量 反序列化
Newtonsoft.Json 经常再用 这样的需求 还是很少用 场景 方法一:根据 Type 反序列化 ; string jsongString = JsonConvert.SerializeObj ...
- 【C#】在datatable中添加一序号列,编号从1依次递增,并且在第一列
详细链接:https://shop499704308.taobao.com/?spm=a1z38n.10677092.card.11.594c1debsAGeak/// <summary> ...