Android UI线程和非UI线程_android在ui线程-程序员宅基地

技术标签: UI线程  Android 开发设计  Android  非UI线程  

 

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

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

  这个主线程负责向UI组件分发事件(包括绘制事件),也是在这个主线程里,你的应用和Android的UI组件(components from the Android UI toolkit (components from the android.widget andandroid.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 andandroid.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对象都会收到同样的方法。(这是一个“一对多”的关系)。

 

参考资料

  官方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

 

  博客:

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

  http://www.cnblogs.com/playing/archive/2011/03/24/1993583.html

 

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/qq_25827845/article/details/52457569

智能推荐

RTX5 | 线程管理01 - 创建线程(静态堆栈方式)_osthreadattr_t-程序员宅基地

文章浏览阅读4.4k次,点赞5次,收藏10次。文章目录一、前言二、代码2.1、main.h2.1、main.c三、DEBUG四、细节补充4.1、使用静态堆栈方式创建的线程不占用RTX5内存池的内存![在这里插入图片描述](https://img-blog.csdnimg.cn/20210527233256628.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dhbGxhY2U4OQ==,siz_osthreadattr_t

嵌入式杂谈之makefile补充-程序员宅基地

文章浏览阅读592次。我看了下自己的文章库存,好像还没有一篇关于Makefile的文章,所以这篇刚好可以弥补自己的缺失。makefile预定义变量预定义变量即系统自带的变量预定义变量作用AR库文件维护程序的名..._makefile 工程师

java中的Properties配置文件_java配置文件properties文件中-程序员宅基地

文章浏览阅读3.6k次。java中的Properties文件配置_java配置文件properties文件中

tocbot.js_使用Tocbot自动生成目录-程序员宅基地

文章浏览阅读4.6k次。越来越长的内容正成为一种规范, 受到了Google和用户的广泛欢迎。 但是,阅读带有大量副标题的长格式内容可能有点令人头疼 。 输入Tocbot ,这是一个基于JavaScript的免费内容生成器表 。 这会在任何页面上自动创建一个固定的目录列表,并在您滚动经过每个标题时更新您的位置。 另请阅读: 使用HTML插槽创建自动生成的目录 主页包括完整的预览以及可用来进行所有设置的文档..._tocbot 得用法

将数组元素顺序颠倒_将具有n个元素的一堆数组的内容前后倒置-程序员宅基地

文章浏览阅读3.2k次。有数组a[n],用java代码将数组元素顺序颠倒实现代码:import java.util.Arrays;public class Test{ public static void main(String[] args) { int [] a = new int[]{ (int)(Math.random() * 1000), (int)(Math.rand_将具有n个元素的一堆数组的内容前后倒置

前端使用QRcode生成二维码_前端qrcode-程序员宅基地

文章浏览阅读2.1k次。在vue中需要生成二维码,这时候我们可以使用qrcode这个插件来完成1. 首先需要安装插件npm install --save qrcode2. 引入使用import QRCode from "qrcode"3. 直接上代码下一篇我会整理一个点击下载二维码的教程,有需要的可以看一下..._前端qrcode

随便推点

数字信号处理基础----傅里叶变换_数字信号处理傅里叶变换-程序员宅基地

文章浏览阅读6.2k次,点赞6次,收藏25次。1 周期矩形脉冲的傅里叶级数_数字信号处理傅里叶变换

RecyclerView实现画廊效果|列表选中位置居中|列表位置固定|第一个项目居中|列表平滑滚动_recyclerview 画廊-程序员宅基地

文章浏览阅读3.8k次,点赞8次,收藏22次。基于RecyclerView实现图片画廊效果, 关键词:图片居中显示,RecyclerView平缓滚动,第一个视图居中,最后一个视图居中_recyclerview 画廊

linux学习之路-nginx初体验_不会linux 可以学习nginx吗-程序员宅基地

文章浏览阅读141次。Nginx安装先到nginx官网下载linux版本的安装包http://nginx.org/en/download.html将安装包传输到linux上,使用tar zxvf 解压nginx安装包1、进入到nginx,直接先执行configure2、安装前置依赖(yum install -y gcc pcre pcre-devel openssl openssl-devel gd gd-devel),重新执行confingure3、使用make4、查看nginx安装目录,代_不会linux 可以学习nginx吗

北理计算机学硕保研,2019计算机保研夏令营经验-上科大、北理、北航、中科院计算所夏令营...-程序员宅基地

文章浏览阅读1.3k次,点赞2次,收藏10次。一、写在前面终于过了9.28,几个月前在和同学吃饭的时候就在说,如果现在是国庆节多好啊,保研就结束了,不用再那么焦虑。保研前就看过网上好多经验帖,就想着等保研结束后把自己的经历与感想写下来,希望能给学弟学妹们一些帮助。在这里十分感谢一路上帮助并鼓励我的家人、老师、学长学姐和同学,是你们对我的帮助让我成功地走下来,走过那段焦虑的时光。以下是我几个月来的收获与体会,希望能对大家有帮助,如果有问题欢迎私..._北理与北航的推免夏令营哪个好通过

JavaScript资源大全中文版(Awesome最新版) 转-程序员宅基地

文章浏览阅读914次,点赞30次,收藏24次。JavaScript资源大全中文版(Awesome最新版)目录前端MVC 框架和库包管理器加载器打包工具测试框架框架断言覆盖率运行器QA 工具基于 Node 的 CMS 框架模板引擎数据可视化编辑器UI输入日历选择文件上传其它提示模态框和弹出框滚动菜单表格/栅格框架手势地图视频/音频动画图片处理ECMAScri..._awesome-javascript

浅谈欧拉函数-程序员宅基地

文章浏览阅读4.3w次,点赞144次,收藏387次。前言欧拉函数听起来很高大上,但其实非常简单,也是NOIP里的一个基础知识,希望大家看完我的博客能有所理解。什么是欧拉函数欧拉函数是小于x的正整数中与x互质的数的个数,一般用φ(x)表示。特殊的,φ(1)=1。如何计算欧拉函数通式: φ(x)=x∏ni=1(1−1pi)∏i=1n(1−1pi)\prod_{i=1}^n{(1-\frac{1}{p_i})} φ(1)=1 其..._欧拉函数

推荐文章

热门文章

相关标签