Android--多线程之进程与线程

简介:

前言

  对于Android程序中,使用多线程的技术是必不可少的,就拿之前最简单的例子来说明,对于Android4.0+的应用而言,访问网络必须另起线程才可以访问。本片博客介绍Android下进程和线程,以及它们的特点及应用,并通过几个Demo来展示Android中简单的线程中操作UI线程的组件。

进程与线程

  一般来说,Android中为一个应用程序开启一个进程进行执行,在这个应用程序中的所有组件,通过单独的线程进行执行,而其中所有的线程,共享该应用程序进程的资源。当一个应用程序启动的时候,Android系统启动一个新的Linux应用程序的进程和一个执行线程。默认情况下,一个应用程序运行中的所有组件运行在相同的进程和线程中,这里的线程一般称为主线程。如果一个应用程序的组件开始的时候,已经存在一个进程,那么应用程序会在与它相同的执行线程中开始这个组件。

进程

  默认情况下,同一应用程序下的所有组件运行在同一进程中,大多数应用程序不应该改变这个。然而,如果需要控制那个进程属于那个组件,可以在AndroidManifest.xml文件中进行配置。一般来说,组件元素:<activity>、<service>、<receiver>、<provider>均支持一个android:process属性,可以设置这个属性让不同的组件单独运行在自己的进程中,也可以使用这个属性使不同的应用程序组件运行在相同的进程中,并共享相同的Linux用户ID和赋予同样的证书。

  Tips:<application>元素也支持android:process属性,用于设置所有的组件。

  Android在内存较低的情况下,会关闭一些优先级较低的进程以增大内存运行更重要的进程,而在这个进程中的所有线程,也会被同时销毁。在内存足够的情况下,Android系统会视图尽可能保持应用程序进程,以达到下次的运行的快速启动,但最终需要移除旧的进程,回收内存用于新的或更重要的进程。通过进程的优先级来判断是否被回收,一般会回收优先级低的进程,以给优先级高的进程腾出资源。

  下面是五类Android进程,他们的优先级顺序排列:

  1. Foreground process:前台进程。
  2. Visible prcess:可见进程。
  3. Service process:服务进程。
  4. Background process:后台进程。
  5. Empty process:空进程。

  Tips:一个进程的优先级是可以变化的。

 

线程

  当应用程序启动时,系统会创建一个执行线程在这个应用程序的的进程中,一般被称为“主线程”。这个线程是非常重要的,因为它负责把事件分发给响应的用户组件,包括绘制事件等,因此主线程又被称为UI线程。系统并不会为每个组件创建一个单独的线程,而是在UI线程中,完成这些组件的初始化的,因此系统回调方法是运行在UI线程中,如click事件。

  当程序执行比较复杂的工作来应对用户交互的时候,哪怕应用程序被正确的执行了,单线程模式也可能会导致运行性能很低下。举例来说,如果一切的应用功能都发生在UI线程中,当执行耗时操作的时候,如访问网络或查询数据,均会阻塞UI先,将导致其他的事件不被分发到事件队列中,包括屏幕绘制事件。导致从用户的角度来看,应用程序死掉了。而在Android系统中,当UI线程被阻塞超过几秒钟(大约是5秒)的时候,会弹出“应用程序没有响应”的对话框,造成用户体验差,可能会迫使用户决定退出你的应用或者干脆直接卸载它。

  此外,Android的UI ToolKit包下的所有组件都不是线程安全的,所以,不能在一个单独的工作线程中操作这些UI组件,必须在UI线程中操作。因此,对于单线程模型,Android有两个规则:

  1. 不能阻塞UI线程
  2. 不能在工作线程中访问Android UI ToolKit包下的组件。

  对于耗时的操作,应该放在单独的线程中。例如:下面通过一个Demo监听按钮点击事件,下载一个图片,从单独的线程中,并显示在一个ImageView中。

复制代码
 1         btnError2.setOnClickListener(new View.OnClickListener() {            
 2             @Override
 3             public void onClick(View v) {
 4                 // 增加一个线程访问网络
 5                 new Thread(new Runnable() {
 6                     @Override
 7                     public void run() {
 8                         // 获取地址下的图片
 9                         Bitmap btm=loadImageFromNetwork("http://ww4.sinaimg.cn/bmiddle/786013a5jw1e7akotp4bcj20c80i3aao.jpg");
10                         imageView1.setImageBitmap(btm);                        
11                     }
12                 }).start();
13                 
14             }
15         });
复制代码

  起初,这似乎是合理的,启动了一个新线程来访问网络,但是它违反了规则二,不能在Android UI主线程之外修改UI组件,而在click中new Thread的是一个工作线程,在工作线程中无法操作UI组件,以上Demo会报错。

  要修正上面的错误,Android提供几种方法可以从其他线程中访问UI线程:

  • Activity.runOnUiThread(Runnable):运行在指定的UI线程上,如果当前线程是UI线程,那么立即执行,如果当前线程不是UI线程,则发布到UI线程的事件队列中。
  • View.post(Runnable):将事件发布到UI线程中,立即被执行。
  • View.postDelayed(Runnanle,long):将事件发布到UI线程中,延迟被执行,延迟数为传递的long参数。

  下面通过两个Dem来通过上面介绍的方法来操作UI组件:

  Activity.runOnUiThread:

复制代码
 1         btnRunOnUiThread.setOnClickListener(new View.OnClickListener() {
 2             
 3             @Override
 4             public void onClick(View v) {
 5                 new Thread(new Runnable() {
 6                     
 7                     @Override
 8                     public void run() {
 9                         final Bitmap btm=loadImageFromNetwork("http://ww4.sinaimg.cn/bmiddle/786013a5jw1e7akotp4bcj20c80i3aao.jpg");
10                         MainActivity.this.runOnUiThread(new Runnable() {                            
11                             @Override
12                             public void run() {
13                                 imageView1.setImageBitmap(btm);                                
14                             }
15                         });
16                     }
17                 }).start();
18             }
19         });
复制代码

  效果演示:

   View.post

复制代码
 1         btnPost.setOnClickListener(new View.OnClickListener() {
 2             
 3             @Override
 4             public void onClick(View v) {
 5                 new Thread(new Runnable() {
 6                     
 7                     @Override
 8                     public void run() {
 9                         final Bitmap btm=loadImageFromNetwork("http://ww1.sinaimg.cn/bmiddle/88ff29e8jw1e7pjnpfxbrj20dp0a90tb.jpg");
10                         imageView1.post(new Runnable() {
11                             
12                             @Override
13                             public void run() {
14                                 // TODO Auto-generated method stub
15                                 imageView1.setImageBitmap(btm);
16                             }
17                         });
18                     }
19                 }).start();                
20             }
21         });
复制代码

  效果演示:

  以上Demo中,通过访问网络获取图片的方法,通过HttpClient实现,不清楚的朋友可以参见博客:HttpClient

  源码下载

 

总结

  虽然上面介绍了几种方式在工作线程中把消息发布到UI线程的消息队列的方式来访问UI组件。但是一般实际的开发当中,这种代码会变的复杂且难于维护。处理更复杂的线程间交互,可以考虑使用Handle+Message,在UI线程中处理工作线程发送过来的消息,还可以继承AsyncTask类来简化工作线程发送消息到主线程中交互UI组件。这两种方式会在接下来的博客中介绍到。



本文转自承香墨影博客园博客,原文链接:http://www.cnblogs.com/plokmju/p/android_ProcessOrThread.html,如需转载请自行联系原作者


相关文章
【Linux进程概念】—— 操作系统中的“生命体”,计算机里的“多线程”
在计算机系统的底层架构中,操作系统肩负着资源管理与任务调度的重任。当我们启动各类应用程序时,其背后复杂的运作机制便悄然展开。程序,作为静态的指令集合,如何在系统中实现动态执行?本文带你一探究竟!
【Linux进程概念】—— 操作系统中的“生命体”,计算机里的“多线程”
|
2月前
|
python3多线程中使用线程睡眠
本文详细介绍了Python3多线程编程中使用线程睡眠的基本方法和应用场景。通过 `time.sleep()`函数,可以使线程暂停执行一段指定的时间,从而控制线程的执行节奏。通过实际示例演示了如何在多线程中使用线程睡眠来实现计数器和下载器功能。希望本文能帮助您更好地理解和应用Python多线程编程,提高程序的并发能力和执行效率。
81 20
Unity多线程使用(线程池)
在C#中使用线程池需引用`System.Threading`。创建单个线程时,务必在Unity程序停止前关闭线程(如使用`Thread.Abort()`),否则可能导致崩溃。示例代码展示了如何创建和管理线程,确保在线程中执行任务并在主线程中处理结果。完整代码包括线程池队列、主线程检查及线程安全的操作队列管理,确保多线程操作的稳定性和安全性。
Python实用技巧:轻松驾驭多线程与多进程,加速任务执行
在Python编程中,多线程和多进程是提升程序效率的关键工具。多线程适用于I/O密集型任务,如文件读写、网络请求;多进程则适合CPU密集型任务,如科学计算、图像处理。本文详细介绍这两种并发编程方式的基本用法及应用场景,并通过实例代码展示如何使用threading、multiprocessing模块及线程池、进程池来优化程序性能。结合实际案例,帮助读者掌握并发编程技巧,提高程序执行速度和资源利用率。
68 0
|
4月前
|
单线程传奇Redis,为何引入多线程?
Redis 4.0 引入多线程支持,主要用于后台对象删除、处理阻塞命令和网络 I/O 等操作,以提高并发性和性能。尽管如此,Redis 仍保留单线程执行模型处理客户端请求,确保高效性和简单性。多线程仅用于优化后台任务,如异步删除过期对象和分担读写操作,从而提升整体性能。
102 1
安卓与iOS开发中的线程管理差异解析
在移动应用开发的广阔天地中,安卓和iOS两大平台各自拥有独特的魅力。如同东西方文化的差异,它们在处理多线程任务时也展现出不同的哲学。本文将带你穿梭于这两个平台之间,比较它们在线程管理上的核心理念、实现方式及性能考量,助你成为跨平台的编程高手。
深入探索Android与iOS的多线程编程差异
在移动应用开发领域,多线程编程是提高应用性能和响应性的关键。本文将对比分析Android和iOS两大平台在多线程处理上的不同实现机制,探讨它们各自的优势与局限性,并通过实例展示如何在这两个平台上进行有效的多线程编程。通过深入了解这些差异,开发者可以更好地选择适合自己项目需求的技术和策略,从而优化应用的性能和用户体验。
Python中的并发编程:探索多线程与多进程的奥秘####
本文深入探讨了Python中并发编程的两种主要方式——多线程与多进程,通过对比分析它们的工作原理、适用场景及性能差异,揭示了在不同应用需求下如何合理选择并发模型。文章首先简述了并发编程的基本概念,随后详细阐述了Python中多线程与多进程的实现机制,包括GIL(全局解释器锁)对多线程的影响以及多进程的独立内存空间特性。最后,通过实例演示了如何在Python项目中有效利用多线程和多进程提升程序性能。 ####
在Java多线程编程中,选择合适的线程创建方法至关重要
【10月更文挑战第20天】在Java多线程编程中,选择合适的线程创建方法至关重要。本文通过案例分析,探讨了继承Thread类和实现Runnable接口两种方法的优缺点及适用场景,帮助开发者做出明智的选择。
63 2
爬取小说资源的Python实践:从单线程到多线程的效率飞跃
本文介绍了一种使用Python从笔趣阁网站爬取小说内容的方法,并通过引入多线程技术大幅提高了下载效率。文章首先概述了环境准备,包括所需安装的库,然后详细描述了爬虫程序的设计与实现过程,包括发送HTTP请求、解析HTML文档、提取章节链接及多线程下载等步骤。最后,强调了性能优化的重要性,并提醒读者遵守相关法律法规。
156 0

相关实验场景

更多
AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等