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进程,他们的优先级顺序排列:
- Foreground process:前台进程。
- Visible prcess:可见进程。
- Service process:服务进程。
- Background process:后台进程。
- Empty process:空进程。
Tips:一个进程的优先级是可以变化的。
线程
当应用程序启动时,系统会创建一个执行线程在这个应用程序的的进程中,一般被称为“主线程”。这个线程是非常重要的,因为它负责把事件分发给响应的用户组件,包括绘制事件等,因此主线程又被称为UI线程。系统并不会为每个组件创建一个单独的线程,而是在UI线程中,完成这些组件的初始化的,因此系统回调方法是运行在UI线程中,如click事件。
当程序执行比较复杂的工作来应对用户交互的时候,哪怕应用程序被正确的执行了,单线程模式也可能会导致运行性能很低下。举例来说,如果一切的应用功能都发生在UI线程中,当执行耗时操作的时候,如访问网络或查询数据,均会阻塞UI先,将导致其他的事件不被分发到事件队列中,包括屏幕绘制事件。导致从用户的角度来看,应用程序死掉了。而在Android系统中,当UI线程被阻塞超过几秒钟(大约是5秒)的时候,会弹出“应用程序没有响应”的对话框,造成用户体验差,可能会迫使用户决定退出你的应用或者干脆直接卸载它。
此外,Android的UI ToolKit包下的所有组件都不是线程安全的,所以,不能在一个单独的工作线程中操作这些UI组件,必须在UI线程中操作。因此,对于单线程模型,Android有两个规则:
- 不能阻塞UI线程
- 不能在工作线程中访问Android UI ToolKit包下的组件。
对于耗时的操作,应该放在单独的线程中。例如:下面通过一个Demo监听按钮点击事件,下载一个图片,从单独的线程中,并显示在一个ImageView中。
btnError2.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// 增加一个线程访问网络
new Thread(new Runnable() {
@Override
public void run() {
// 获取地址下的图片
Bitmap btm=loadImageFromNetwork("http://ww4.sinaimg.cn/bmiddle/786013a5jw1e7akotp4bcj20c80i3aao.jpg");
imageView1.setImageBitmap(btm);
}
}).start(); }
});
起初,这似乎是合理的,启动了一个新线程来访问网络,但是它违反了规则二,不能在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:
btnRunOnUiThread.setOnClickListener(new View.OnClickListener() { @Override
public void onClick(View v) {
new Thread(new Runnable() { @Override
public void run() {
final Bitmap btm=loadImageFromNetwork("http://ww4.sinaimg.cn/bmiddle/786013a5jw1e7akotp4bcj20c80i3aao.jpg");
MainActivity.this.runOnUiThread(new Runnable() {
@Override
public void run() {
imageView1.setImageBitmap(btm);
}
});
}
}).start();
}
});
效果演示:
View.post
btnPost.setOnClickListener(new View.OnClickListener() { @Override
public void onClick(View v) {
new Thread(new Runnable() { @Override
public void run() {
final Bitmap btm=loadImageFromNetwork("http://ww1.sinaimg.cn/bmiddle/88ff29e8jw1e7pjnpfxbrj20dp0a90tb.jpg");
imageView1.post(new Runnable() { @Override
public void run() {
// TODO Auto-generated method stub
imageView1.setImageBitmap(btm);
}
});
}
}).start();
}
});
效果演示:
以上Demo中,通过访问网络获取图片的方法,通过HttpClient实现,不清楚的朋友可以参见博客:HttpClient。
总结
虽然上面介绍了几种方式在工作线程中把消息发布到UI线程的消息队列的方式来访问UI组件。但是一般实际的开发当中,这种代码会变的复杂且难于维护。处理更复杂的线程间交互,可以考虑使用Handle+Message,在UI线程中处理工作线程发送过来的消息,还可以继承AsyncTask类来简化工作线程发送消息到主线程中交互UI组件。这两种方式会在接下来的博客中介绍到。
Android--多线程之进程与线程的更多相关文章
- C# - 多线程 之 进程与线程
并行~并发 并发 Concurrency,逻辑上的同时发生,一个处理器(在不同时刻或者说在同一时间间隔内)"同时"处理多个任务.宏观上是并发的,微观上是按排队等待.唤醒.执行的步骤 ...
- Java多线程之进程和线程
在并发编程中有两个基本的概率就是进程和线程.在Java编程中并发编程更多的是关注线程.但是进程也是很重要的. 一个计算机一般会有很多活跃的进程和线程.有一点是没有疑问的在单核系统中,任何时候实际上都是 ...
- day10-02_多线程之进程与线程的pid
一.多个线程之间PID的区别 主进程跟线程的pid是一样的 from threading import Thread from multiprocessing import Process impor ...
- Android 多线程: 完全解析线程池ThreadPool原理&使用
目录 1. 简介 2. 工作原理 2.1 核心参数 线程池中有6个核心参数,具体如下 上述6个参数的配置 决定了 线程池的功能,具体设置时机 = 创建 线程池类对象时 传入 ThreadPoolExe ...
- 【Android多线程】Thread和线程池
https://www.bilibili.com/video/av65170691?p=3 (本文为此视频听课笔记) 一.为什么要使用多线程 二.Thread 2.1 通过继承Thread类 2.2 ...
- Android中的进程与线程
四大组件都是运行在主线程中 1.前台进程:用户正在交互,相当于Activity执行了onResume方法 2.可见进程:用户失去了焦点,相当于Activity执行了onPause方法 3.服务进程:运 ...
- [转]Android进程与线程基本知识
转自:http://www.cnblogs.com/hanyonglu/archive/2012/04/12/2443262.html 本文介绍Android平台中进程与线程的基本知识. 很早的时候就 ...
- Python全栈【进程、线程】
Python全栈[进程.线程] 本节内容: 进程 线程 协程 I/O多路复用 进程 1.进程就是一个程序在一个数据集上的一次动态执行过程,进程是资源分配的最小单元. 2.进程一般由程序.数据集.进程控 ...
- 什么是进程And线程
原创 2015年02月01日 11:49:01 学习.net 时遇到了两个新词汇:进程和线程.书上的太深奥,就查了查资料,整合下,希望对大家有帮助. [比喻]:用手去抓苹果,很显然一根手指是不行, ...
- 【Python】进程和线程
多进程 多线程 ThreadLocal 进程vs线程 分布式进程 Top 学习廖老师的py官网的笔记 多任务的实现方式有三种方式: 1.多进程 2.多线程 3.多进程+多线程(这种比较复杂,实际很少采 ...
随机推荐
- RPA基础
RPA是什么 软件机器人 RPA是基于计算机操作系统的工作界面,自动识别UI,完成预先设定的工作流程的软件机器人 全自动 自动的操作整个工作流程,用软件的方式代替人力,完成大量的重复性的手工操作, ...
- #实验三 敏捷开发与XP实践---实验报告
一.实验三 敏捷开发与XP实践-1 1.实验要求 -实验三 敏捷开发与XP实践 http://www.cnblogs.com/rocedu/p/4795776.html, Eclipse的内容替换成I ...
- Meanshift均值漂移算法
通俗理解Meanshift均值漂移算法 Meanshift车手?? 漂移?? 秋名山??? 不,不,他是一组算法, 今天我就带大家来了解一下机器学习中的Meanshift均值漂移. Mea ...
- ajax用户是否存在
$(function(){ $("#username").blur(function(){ var usernameInput=$(this).val(); $.post( &qu ...
- WinDbg分析Dump常用方法和命令
记录下自己使用WinDbg分析Dump时常用的一些方法和命令 !analyze -v //找出出错的堆 .exrc //找到程序崩溃的位置 !heap //打印出错函数的局部位置 !for_each_ ...
- 流量控制与RateLimiter
一背景 如何提高系统的稳定性,简单来说除了加机器外就是服务降级.限流.加机器就是常说的分布式,从整个架构的稳定性角度看,一般SOA每个接口的所能提供的单位时间服务能力是有上限.假如超过服务能力,一般会 ...
- 前台js接收后台的json数据
后台返回的json数据,如php的: return json_encode($data); 在前台 js接收如下: function json2object(str){ var jsstr = str ...
- MySQL数据库(一)
一:MySQL的简单介绍 MySQL属于关系型数据库,数据是以行和列的形式去存储(表),表中的每一行叫一条记录,表中的每一列叫一个字段,表和表之间的逻辑关联叫关系. 二:MySQL的基本操作 (一)M ...
- <笔记>原生PHP访问TP模板变量
在模板中,原生PHP可以直接访问模板变量,不过如果模板变量是数组,要访问数组中元素时不能使用"."符号,只能通过数组['元素名']的方式
- 无知小子踏入python web大门
学习python flask的第一天,费劲我小白的脑子,总算完成了环境配置 详情如下,其他小白误走弯路,希望和我一样爱好python的人坚信:python或许是最好的语言! 那么,开始喽,有不对的地方 ...