为什么说android UI操作不是线程安全的 分类: Android 2014-09-23 21:08 1357人阅读 评论(0) 收藏 举报 目录(?)[+] 可能在非UI线程中刷新界面的时候,U

转载 2015年07月10日 10:09:53

为什么说android UI操作不是线程安全的

分类: Android 1357人阅读 评论(0) 收藏 举报

目录(?)[+]

可能在非UI线程中刷新界面的时候,UI线程(或者其他非UI线程)也在刷新界面,这样就导致多个界面刷新的操作不能同步,导致线程不安全。

1、为什么说invalidate()不能直接在线程中调用?
2、它是怎么违背单线程的?
3、android ui为什么说不是线程安全的?
4、android ui操作为什么一定要在UI线程中执行?

 

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为什么说不是线程安全的?
答:android UI 中提供invalidate()来更新界面,而invalidate()方法是线程不安全。
4、android ui操作为什么一定要在UI线程中执行?
答:UI主线程是更新UI界面的,更新了界面才能看到运行的效果。
     再者Android UI操作并不是线程安全的并且这些操作必须在UI线程中执行。如果在子线程中直接修改UI,会导致异常。




UI线程及Android的单线程模型原则

  当应用启动,系统会创建一个主线程(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线程

 

  系统不会为每个组件单独创建线程,在同一个进程里的UI组件都会在UI线程里实例化,系统对每一个组件的调用都从UI线程分发出去

  结果就是,响应系统回调的方法(比如响应用户动作的onKeyDown()和各种生命周期回调)永远都是在UI线程里运行。

 

  当App做一些比较重(intensive)的工作的时候,除非你合理地实现,否则单线程模型的performance会很poor。

  特别的是,如果所有的工作都在UI线程,做一些比较耗时的工作比如访问网络或者数据库查询,都会阻塞UI线程导致事件停止分发(包括绘制事件)。对于用户来说,应用看起来像是卡住了,更坏的情况是,如果UI线程blocked的时间太长(大约超过5秒),用户就会看到ANRapplication not responding)的对话框。

  另外,Andoid UI toolkit并不是线程安全的,所以你不能从非UI线程来操纵UI组件。你必须把所有的UI操作放在UI线程里,所以Android的单线程模型有两条原则:

  1.不要阻塞UI线程。

  2.不要在UI线程之外访问Android UI toolkit(主要是这两个包中的组件:android.widget and android.view)。

 

使用Worker线程

  根据单线程模型的两条原则,首先,要保证应用的响应性,不能阻塞UI线程,所以当你的操作不是即时的那种(not instantaneous),你应该把他们放进单另的线程中(叫做background或者叫worker线程)。

  比如点击按钮后,下载一个图片然后在ImageView中展示:

复制代码
public void onClick(View v) {
    new Thread(new Runnable() {
        public void run() {
            Bitmap b = loadImageFromNetwork("http://example.com/image.png");
            mImageView.setImageBitmap(b);
        }
    }).start();
}
复制代码

 

  这段代码用新的线程来处理网络操作,但是它违反了第二条原则:

  Do not access the Android UI toolkit from outside the UI thread.

  从非UI线程访问UI组件会导致未定义和不能预料的行为

 

  为了解决这个问题,Android提供了一些方法,从其他线程访问UI线程:

 

  比如,上面这段代码可以这么改:

复制代码
public void onClick(View v) {
    new Thread(new Runnable() {
        public void run() {
            final Bitmap bitmap = loadImageFromNetwork("http://example.com/image.png");
            mImageView.post(new Runnable() {
                public void run() {
                    mImageView.setImageBitmap(bitmap);
                }
            });
        }
    }).start();
}
复制代码

 

  这么改之后就是线程安全的了。

  但是,当操作变得复杂的时候,这种代码会变得非常复杂,为了处理非UI线程和UI线程之间更加复杂的交互,可以考虑在worker线程中使用一个Handler,来处理UI线程中传来的消息。

  也可以继承这个类AsyncTask 。

 

Communicating with the UI Thread

  只有在UI线程中的对象才能操作UI线程中的对象,为了将非UI线程中的数据传送到UI线程,可以使用一个 Handler运行在UI线程中。

  Handler是Android framework中管理线程的部分,一个Handler对象负责接收消息然后处理消息。

  你可以为一个新的线程创建一个Handler,也可以创建一个Handler然后将它和已有线程连接。

  如果你将一个Handler和你的UI线程连接,处理消息的代码就将会在UI线程中执行。

 

  可以在你创建线程池的类的构造方法中实例化Handler的对象,然后用全局变量存储这个对象。

  要和UI线程连接,实例化Handler的时候应该使用Handler(Looper) 这个构造方法。

  这个构造方法使用了一个 Looper 对象,这是Android系统中线程管理的framework的另一个部分。

  当你用一个特定的 Looper实例来创建一个 Handler时,这个 Handler就运行在这个 Looper的线程中。

 

  在Handler中,要覆写handleMessage() 方法。Android系统会在Handler管理的相应线程收到新消息时调用这个方法

  一个特定线程的所有Handler对象都会收到同样的方法。(这是一个“一对多”的关系)。

相关文章推荐

CABasicAnimation的基本使用方法(移动·旋转·放大·缩小) 分类: iPhone 2014-04-07 09:52 548人阅读 评论(0) 收藏 举报 目录(?)[+] 博主:最近i

博主:最近iOS开发中用到CoreAnimation的framework来做动画效果,虽然以前也用过,但一直没有系统学习过,今天看到一篇非常详细的博文(虽然是日语,但真的写的很好),在此翻译出来供大家...

C# 中的委托和事件 分类: .NET 接口+泛型+委托+继承 2011-08-30 10:09 20人阅读 评论(0) 收藏 举报 引言 委托 和 事件在 .Net Framework中的应用非

C# 中的委托和事件 分类: .NET 接口+泛型+委托+继承2011-08-30 10:09 20人阅读 评论(0) 收藏 举报   引言 委托 和 事件在 .Net F...
  • A_post
  • A_post
  • 2011年09月05日 19:26
  • 1275

为什么说android UI操作不是线程安全的

可能在非UI线程中刷新界面的时候,UI线程(或者其他非UI线程)也在刷新界面,这样就导致多个界面刷新的操作不能同步,导致线程不安全。 1、为什么说invalidate()不能直接在线程中...

为什么说android UI操作不是线程安全的

为什么说android UI操作不是线程安全的

系统学习深度学习(七)--主流深度学习开源框架对比 2017-01-23 11:05 2292人阅读 评论(0) 收藏 举报 分类: 深度学习(30) 目录(?)[+] 转自:http://b

系统学习深度学习(七)--主流深度学习开源框架对比 2017-01-23 11:05 2292人阅读 评论(0) 收藏 举报  分类: 深度学习(30)  ...

android UI操作不是线程安全的

转自:http://blog.csdn.net/lvxiangan/article/details/39504145 为什么说android UI操作不是线程安全的 2014-09...
  • ml_1995
  • ml_1995
  • 2017年03月23日 01:11
  • 83

STM32 use microlib是干什么的 2016-04-25 23:13 1298人阅读 评论(0) 收藏 举报 分类: STM32(15) 版权声明:本文为博主原创文章,未经博主允许

STM32 use microlib是干什么的 2016-04-25 23:13 1298人阅读 评论(0) 收藏 举报  分类: STM32(15)  版...

国嵌实验:触摸屏 分类: mini2440 裸机程序 2011-09-27 15:28 17人阅读 评论(0) 收藏 举报 #define GLOBAL_CLK 1 #include <st

#define GLOBAL_CLK1 #include #include #include "def.h" #include "option.h" #include "2440addr...

安装mysql Install/Remove of the Service Denied!错误的解决办法 2013-11-05 10:08 81426人阅读 评论(6) 收藏 举报 分类: m

安装mysql Install/Remove of the Service Denied!错误的解决办法 2013-11-05 10:08 81426人阅读 评论(6) 收藏 举报  分类...

EventBus使用详解(二)——EventBus使用进阶 2014-11-04 16:45 88833人阅读 评论(81) 收藏 举报 分类: 5、andriod开发(149) 版权声明:本文

EventBus使用详解(二)——EventBus使用进阶 2014-11-04 16:45 88833人阅读 评论(81) 收藏 举报  分类: 5、andriod开发...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:为什么说android UI操作不是线程安全的 分类: Android 2014-09-23 21:08 1357人阅读 评论(0) 收藏 举报 目录(?)[+] 可能在非UI线程中刷新界面的时候,U
举报原因:
原因补充:

(最多只允许输入30个字)