博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
android UI 进程
阅读量:3624 次
发布时间:2019-05-21

本文共 2398 字,大约阅读时间需要 7 分钟。

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

  当应用启动,系统会创建一个主线程(main thread)

  这个主线程负责向UI组件分发事件(包括绘制事件),也是在这个主线程里,你的应用和Android的UI组件(components from the Android UI toolkit (components from the and packages))发生交互。

  所以main thread也叫UI thread也即UI线程

 

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

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

 

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

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

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

  1.不要阻塞UI线程。

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

 

使用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线程中使用一个,来处理UI线程中传来的消息。

  也可以继承这个类 。

 

Communicating with the UI Thread

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

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

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

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

 

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

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

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

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

 

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

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

 

参考资料

  官方Training: 与UI线程通信:

  

  Guides: Processes and Threads

  

 

  类参考:

  

  

  

 

  博客:

  Android的线程使用来更新UI----Thread、Handler、Looper、TimerTask等:

  

转载地址:http://pmkun.baihongyu.com/

你可能感兴趣的文章
Java代码设计模式讲解二十三种设计模式
查看>>
IDEA的使用教程二:idea的内置快捷键和idea的代码模板设置
查看>>
idea使用教程三:(创建web项目)
查看>>
Window localStorage 属性(永久储存网站的数据)
查看>>
jQuery中的 $(window) load()与$(document) ready()以及jquery $(document) ready() 与window onload 的区别
查看>>
Java创建URL后台访问接口,返回数据(Http请求-HttpClient方法)
查看>>
项目部署调用接口传参编码问题
查看>>
idea每次打开都是选择项目页面
查看>>
IDEA修改文件后出现星号
查看>>
设计模式——单例模式
查看>>
工厂模式
查看>>
ClassUtils——可以由一个接口查找到所有的实现类,也可 以由父类查找到所有的子类
查看>>
责任链模式
查看>>
算法(1)——流程图和DNS图
查看>>
leetcode——442
查看>>
sentinel 控制台讲解-流控规则--阈值类型:QPS 流控模式:直接 流控效果:快速失败
查看>>
Java语言程序设计(基础篇)第十版 5.3-6
查看>>
Java语言程序设计(基础篇)第十版 5.7
查看>>
Java语言程序设计(基础篇)第十版 5.8 5.9
查看>>
Java语言程序设计(基础篇)第十版 5.10-11
查看>>