AndroidUI线程和非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秒),用户就会看到ANR(application 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中展示:

 
 
 
  1. public void onClick(View v) { 
  2.     new Thread(new Runnable() { 
  3.         public void run() { 
  4.             Bitmap b = loadImageFromNetwork("http://example.com/image.png"); 
  5.             mImageView.setImageBitmap(b); 
  6.         } 
  7.     }).start(); 

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

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

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

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

  • Activity.runOnUiThread(Runnable)
  • View.post(Runnable)
  • View.postDelayed(Runnable, long)

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

 
 
 
  1. public void onClick(View v) { 
  2.     new Thread(new Runnable() { 
  3.         public void run() { 
  4.             final Bitmap bitmap = loadImageFromNetwork("http://example.com/image.png"); 
  5.             mImageView.post(new Runnable() { 
  6.                 public void run() { 
  7.                     mImageView.setImageBitmap(bitmap); 
  8.                 } 
  9.             }); 
  10.         } 
  11.     }).start(); 

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

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

也可以继承这个类AsyncTask 。

与UI线程通信

只有在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对象都会收到同样的方法。(这是一个“一对多”的关系)。

参考资料

官方Training: 与UI线程通信:

http://developer.android.com/training/multiple-threads/communicate-ui.html

Guides: Processes and Threads

http://developer.android.com/guide/components/processes-and-threads.html

类参考:

http://developer.android.com/reference/android/os/Looper.html

http://developer.android.com/reference/android/os/Handler.html

http://developer.android.com/reference/android/os/HandlerThread.html

【移动开发视频课程推荐】

  • iOS培训之Objective-C基础视频教程(40集)
  • Cocos2d-x从零开始【5天掌握跨平台游戏开发利器】(12集)
  • Objective C编程基础(24集)
  • Android技术轻松入门课程(12集)
  • 微信开放平台-Android应用接入(4集)
  • Cocos2d-x跨平台游戏开发入门基础(29集)
  • iOS开发视频教程-iOS网络编程【高级篇】(39集)
  • 移动应用用户体验设计高级课程(60集)
  • 从零学习iOS开发–UI多视图(30集)
  • iOS开发视频教程【基础入门篇】

当前题目:AndroidUI线程和非UI线程
浏览地址:http://www.shufengxianlan.com/qtweb/news16/360916.html

网站建设、网络推广公司-创新互联,是专注品牌与效果的网站制作,网络营销seo公司;服务项目有等

广告

声明:本网站发布的内容(图片、视频和文字)以用户投稿、用户转载内容为主,如果涉及侵权请尽快告知,我们将会在第一时间删除。文章观点不代表本网站立场,如需处理请联系客服。电话:028-86922220;邮箱:631063699@qq.com。内容未经允许不得转载,或转载时需注明来源: 创新互联