1. Android 进程
在了解Android 线程 之前得先了解一下Android 的进程。当一个程序第一次启动的时候,Android 会启动一个LINUX进程和一个主线程 。默认的情况下,所有该程序的组件都将在该进程和线程 中运行。
同时,Android 会为每个应用程序分配一个单独的LINUX用户。Android 会尽量保留一个正在运行进程,只在内存资源出现不足时,Android 会尝试停止一些进程从而释放足够的资源给其他新的进程使用, 也能保证用户正在访问的当前进程有足够的资源去及时地响应用户的事件。Android 会根据进程中运行的组件类别以及组件的状态来判断该进程的重要性,Android 会首先停止那些不重要的进程。按照重要性从高到低一共有五个级别:
前台进程
前台进程是用户当前正在使用的进程。只有一些前台进程可以在任何时候都存在。他们是最后一个被结束的,当内存低到根本连他们都不能运行的时候。一般来说, 在这种情况下,设备会进行内存调度,中止一些前台进程来保持对用户交互的响应。
可见进程
可见进程不包含前台的组件但是会在屏幕上显示一个可见的进程是的重要程度很高,除非前台进程需要获取它的资源,不然不会被中止。
服务进程
运 行着一个通过startService() 方法启动的service,这个service不属于上面提到的2种更高重要性的。service所在的进程虽然对用户不是直接可见的,但是他们执行了用 户非常关注的任务(比如播放mp3,从网络下载数据)。只要前台进程和可见进程有足够的内存,系统不会回收他们。
后台进程
运 行着一个对用户不可见的activity(调用过 onStop() 方法).这些进程对用户体验没有直接的影响,可以在服务进程、可见进程、前台进 程需要内存的时候回收。通常,系统中会有很多不可见进程在运行,他们被保存在LRU (least recently used) 列表中,以便内存不足的时候被第一时间回收。如果一个activity正 确的执行了它的生命周期,关闭这个进程对于用户体验没有太大的影响。
空进程
未运行任何程序组件。运行这些进程的唯一原因是作为一个缓存,缩短下次程序需要重新使用的启动时间。系统经常中止这些进程,这样可以调节程序缓存和系统缓存的平衡。
Android 对进程的重要性评级的时候,选取它最高的级别。另外,当被另外的一个进程依赖的时候,某个进程的级别可能会增高。一个为其他进程服务的进程永远不会比被服 务的进程重要级低。因为服务进程比后台activity进程重要级高,因此一个要进行耗时工作的activity最好启动一个service来做这个工 作,而不是开启一个子进程――特别是这个操作需要的时间比activity存在的时间还要长的时候。例如,在后台播放音乐,向网上上传摄像头拍到的图片, 使用service可以使进程最少获取到“服务进程”级别的重要级,而不用考虑activity目前是什么状态。broadcast receivers做费时的工作的时候,也应该启用一个服务而不是开一个线程 。
2. 单线程 模型
当一个程序第一次启动时,Android 会同时启动一个对应的主线程 (Main Thread),主线程 主要负责处理与UI相关的事件,如用户的按键事件,用户接触屏幕的事件以及屏幕绘图事件,并把相关的事件分发到对应的组件进行处理。所以主线程 通常又被叫做UI线程 。在开发Android 应用时必须遵守单线程 模型的原则: Android UI操作并不是线程 安全的并且这些操作必须在UI线程 中执行。
2.1 子线程 更新UI
Android 的UI是单线程 (Single-threaded)的。为了避免拖住GUI,一些较费时的对象应该交给独立的线程 去执行。如果幕后的线程 来执行UI对象,Android 就会发出错误讯息
CalledFromWrongThreadException 。以后遇到这样的异常抛出时就要知道怎么回事了!
2.2 Message Queue
在单线程 模型下,为了解决类似的问题,Android 设计了一个Message Queue(消息队列), 线程 间可以通过该Message Queue并结合Handler和Looper组件进行信息交换。下面将对它们进行分别介绍:
1. Message
Message消息,理解为线程 间交流的信息,处理数据后台线程 需要更新UI,则发送Message内含一些数据给UI线程 。
2. Handler
Handler处理者,是Message的主要处理者,负责Message的发送,Message内容的执行处理。后台线程 就是通过传进来的Handler对象引用来sendMessage(Message) 。而使用Handler,需要implement 该类的 handleMessage(Message)
方法,它是处理这些Message的操作内容,例如Update UI。通常需要子类化Handler来实现handleMessage方法。
3. Message Queue
Message Queue消息队列,用来存放通过Handler发布的消息,按照先进先出执行。
每个message queue都会有一个对应的Handler。Handler会向message queue通过两种方法发送消息:sendMessage或post。这两种消息都会插在message queue队尾并按先进先出执行。但通过这两种方法发送的消息执行的方式略有不同:通过sendMessage发送的是一个message对象,会被 Handler的handleMessage()函数处理;而通过post方法发送的是一个runnable对象,则会自己执行。
4. Looper
Looper是每条线程 里的Message Queue的管家。Android 没有Global的Message Queue,而Android 会自动替主线程 (UI线程 )建立Message Queue,但在子线程 里并没有建立Message Queue。所以调用Looper.getMainLooper()得到的主线程 的Looper不为NULL,但调用Looper.myLooper()得到当前线程 的Looper就有可能为NULL。
对于子线程 使用Looper,API Doc提供了正确的使用方法:
class LooperThread extends Thread {
public Handler mHandler;
public void run() {
Looper.prepare(); //创建本线程 的Looper并创建一个MessageQueue
mHandler = new Handler() {
public void handleMessage(Message msg) {
// process incoming messages here
}
};
Looper.loop(); //开始运行Looper,监听Message Queue
}
}
这个Message机制的大概流程:
1. 在Looper.loop()方法运行开始后,循环地按照接收顺序取出Message Queue里面的非NULL的Message。
2. 一开始Message Queue里面的Message都是NULL的。当Handler.sendMessage(Message)到Message Queue,该函数里面设置了那个Message对象的target属性是当前的Handler对象。随后Looper取出了那个Message,则调用 该Message的target指向的Hander的dispatchMessage函数对Message进行处理。
在dispatchMessage方法里,如何处理Message则由用户指定,三个判断,优先级从高到低:
1) Message里面的Callback,一个实现了Runnable接口的对象,其中run函数做处理工作;
2) Handler里面的mCallback指向的一个实现了Callback接口的对象,由其handleMessage进行处理;
3) 处理消息Handler对象对应的类继承并实现了其中handleMessage函数,通过这个实现的handleMessage函数处理消息。
由此可见,我们实现的handleMessage方法是优先级最低的!
3. Handler处理完该Message (update UI) 后,Looper则设置该Message为NULL,以便回收!
在网上有很多文章讲述主线程 和其他子线程 如何交互,传送信息,最终谁来执行处理信息之类的,个人理解是最简单的方法——判断Handler对象里面的Looper对象是属于哪条线程 的,则由该线程 来执行!
1. 当Handler对象的构造函数的参数为空,则为当前所在线程 的Looper;
2. Looper.getMainLooper()得到的是主线程 的Looper对象,Looper.myLooper()得到的是当前线程 的Looper对象。
现在来看一个例子,模拟从网络获取数据,加载到ListView的过程:
public class ListProgressDemo extends ListActivity {
@Override
public void onCreate(Bundle savedInstanceState) {
super .onCreate(savedInstanceState);
setContentView(R.layout.listprogress);
((Button) findViewById(R.id.load_Handler)).setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View view) {
data = null ;
data = new ArrayList<String>();
adapter = null ;
showDialog(PROGRESS_DIALOG);
new ProgressThread(handler, data).start();
}
});
}
@Override
protected Dialog onCreateDialog(int id) {
switch (id) {
case PROGRESS_DIALOG:
return ProgressDialog.show(this , "" ,
"Loading. Please wait..." , true );
default : return null ;
}
}
private class ProgressThread extends Thread {
private Handler handler;
private ArrayList<String> data;
public ProgressThread(Handler handler, ArrayList<String> data) {
this .handler = handler;
this .data = data;
}
@Override
public void run() {
for (int i=0 ; i<8 ; i++) {
data.add("ListItem" ); //后台数据处理
try {
Thread.sleep(100 );
}catch (InterruptedException e) {
Message msg = handler.obtainMessage();
Bundle b = new Bundle();
b.putInt("state" , STATE_ERROR);
msg.setData(b);
handler.sendMessage(msg);
}
}
Message msg = handler.obtainMessage();
Bundle b = new Bundle();
b.putInt("state" , STATE_FINISH);
msg.setData(b);
handler.sendMessage(msg);
}
}
// 此处甚至可以不需要设置 Looper,因为 Handler默认就使用当前线程 的 Looper
private final Handler handler = new Handler(Looper.getMainLooper()) {
public void handleMessage(Message msg) { // 处理Message,更新ListView
int state = msg.getData().getInt("state" );
switch (state){
case STATE_FINISH:
dismissDialog(PROGRESS_DIALOG);
Toast.makeText(getApplicationContext(),
"加载完成!" ,
Toast.LENGTH_LONG)
.show();
adapter = new ArrayAdapter<String>(getApplicationContext(),
android .R.layout.simple_list_item_1,
data );
setListAdapter(adapter);
break ;
case STATE_ERROR:
dismissDialog(PROGRESS_DIALOG);
Toast.makeText(getApplicationContext(),
"处理过程发生错误!" ,
Toast.LENGTH_LONG)
.show();
adapter = new ArrayAdapter<String>(getApplicationContext(),
android .R.layout.simple_list_item_1,
data );
setListAdapter(adapter);
break ;
default :
}
}
};
private ArrayAdapter<String> adapter;
private ArrayList<String> data;
private static final int PROGRESS_DIALOG = 1 ;
private static final int STATE_FINISH = 1 ;
private static final int STATE_ERROR = -1 ;
}
这个例子,我自己写完后觉得还是有点乱,要稍微整理才能看明白线程 间交互的过程以及数据的前后变化。随后了解到AsyncTask类,相应修改后就很容易明白了!
2.3 AsyncTask
AsyncTask版:
((Button) findViewById(R.id.load_AsyncTask)).setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View view) {
data = null ;
data = new ArrayList<String>();
adapter = null ;
//显示ProgressDialog放到AsyncTask.onPreExecute()里
//showDialog(PROGRESS_DIALOG);
new ProgressTask().execute(data);
}
});
private class ProgressTask extends AsyncTask<ArrayList<String>, Void, Integer> {
/* 该方法将在执行实际的后台操作前被UI thread调用。可以在该方法中做一些准备工作,如在界面上显示一个进度条。*/
@Override
protected void onPreExecute() {
// 先显示ProgressDialog
showDialog(PROGRESS_DIALOG);
}
/* 执行那些很耗时的后台计算工作。可以调用publishProgress方法来更新实时的任务进度。 */
@Override
protected Integer doInBackground(ArrayList<String>... datas) {
ArrayList<String> data = datas[0 ];
for (int i=0 ; i<8 ; i++) {
data.add("ListItem" );
}
return STATE_FINISH;
}
/* 在doInBackground 执行完成后,onPostExecute 方法将被UI thread调用,
* 后台的计算结果将通过该方法传递到UI thread.
*/
@Override
protected void onPostExecute(Integer result) {
int state = result.intValue();
switch (state){
case STATE_FINISH:
dismissDialog(PROGRESS_DIALOG);
Toast.makeText(getApplicationContext(),
"加载完成!" ,
Toast.LENGTH_LONG)
.show();
adapter = new ArrayAdapter<String>(getApplicationContext(),
android .R.layout.simple_list_item_1,
data );
setListAdapter(adapter);
break ;
case STATE_ERROR:
dismissDialog(PROGRESS_DIALOG);
Toast.makeText(getApplicationContext(),
"处理过程发生错误!" ,
Toast.LENGTH_LONG)
.show();
adapter = new ArrayAdapter<String>(getApplicationContext(),
android .R.layout.simple_list_item_1,
data );
setListAdapter(adapter);
break ;
default :
}
}
Android 另外提供了一个工具类:AsyncTask。它使得UI thread的使用变得异常简单。它使创建需要与用户界面交互的长时间运行的任务变得更简单,不需要借助线程 和Handler即可实现。
1) 子类化AsyncTask
2) 实现AsyncTask中定义的下面一个或几个方法
onPreExecute() 开始执行前的准备工作;
doInBackground(Params...) 开始执行后台处理,可以调用publishProgress方法来更新实时的任务进度;
onProgressUpdate(Progress...) 在publishProgress方法被调用后,UI thread将调用这个方法从而在界面上展示任务的进展情况,例如通过一个进度条进行展示。
onPostExecute(Result) 执行完成后的操作,传送结果给UI 线程 。
这4个方法都不能手动调用。而且除了doInBackground(Params...)方法,其余3个方法都是被UI线程 所调用的,所以要求:
1) AsyncTask的实例必须在UI thread中创建;
2) AsyncTask.execute方法必须在UI thread中调用;
同时要注意:该task只能被执行一次,否则多次调用时将会出现异常。而且是不能手动停止的,这一点要注意,看是否符合你的需求!
在使用过程中,发现AsyncTask的构造函数的参数设置需要看明白:AsyncTask<Params, Progress, Result>
Params对应doInBackground(Params...)的参数类型。而new AsyncTask().execute(Params... params),就是传进来的Params数据,你可以execute(data)来传送一个数据,或者execute(data1, data2, data3)这样多个数据。
Progress对应onProgressUpdate(Progress...)的参数类型;
Result对应onPostExecute(Result)的参数类型。
当以上的参数类型都不需要指明某个时,则使用Void,注意不是void。不明白的可以参考上面的例子,或者API Doc里面的例子。
----------------
本文的相当内容摘录于《浅析Android 线程 模型一 --- 转 》,但对于Message机制的流程理解则在参考《android 中Message机制的灵活应用 》后修改了!
相关推荐
Cobalt Strike4.0安装包(内附中文版)
1.什么是 Cobalt Strike Cobalt Strike 是一个为对手模拟和红队行动而设计的平台,主要用于执行有目标的攻击和模拟高级威胁 者的后渗透行动。 Cobalt Strike已经不再使用MSF而是作为单独的平台使用,它分为客户端与服务端,服务端是一个,客户端可以有多个,可被团队进行分布式协团操作。集成了端口转发、扫描多模式端口Listener、Windows exe程序生成、W...
Android Handler Message多线程实例
什么是Handler handler通俗一点讲就是用来在各个进程之间发送数据的处理对象。在任何进程中,只要获得了另一个进程的handler则可以通过 handler.sendMessage(message)方法向那个进程发送数据。基于这个机制,我们在处理多线程的时候可以新
Excel药品说明书数据库:从零开始搭建医药数据查询系统(附完整模板)
本文详细介绍了如何从零开始搭建Excel药品说明书数据库,提供完整的医药数据查询系统模板。涵盖数据库架构设计、数据清洗标准化、智能查询系统搭建及维护优化,帮助医药从业者高效管理药品信息,提升查询速度和准确性。
Android系统分析之带着问题看Handler
1 Handler问题三连:是什么?有什么用?为什么要用,不用行不行? 1.1 Handler是什么? 答:Handler是Android FrameWork架构中的一个基础组件,用于子线程与主线程间的通信,实现一套非阻塞的消息创建、传递、处理机制。 1.2 Handler有什么用? 答:把子线程中的UI更新信息传递给主线程(UI线程),以此完成UI更新操作。 1.3 Handler为什么要用,不用行不行? 答: 2 Android UI更新机制(GUI) 为何设计成了单线程的? 答: 3 真的只能在主(U
CentOS7全隔离环境部署Nvidia Tesla A100 40G驱动与CUDA工具包实战
本文详细介绍了在CentOS7全隔离环境下部署Nvidia Tesla A100 40G显卡驱动与CUDA工具包的实战经验。通过构建本地YUM仓库、解决驱动依赖问题以及三重验证法,确保Tesla A100与CUDA 11.7的完美兼容。同时分享了Anaconda3离线部署技巧,帮助用户在隔离环境中高效搭建Python GPU开发环境。
糖果【贪心】
【问题描述】 有N(1≤N <100,000)N(1≤N~<100,000)N(1≤N <100,000)种不同类型的糖果,每种糖果数量无限多。第i种糖果每颗的价格是Pi(1≤Pi≤1018),有Ci(1≤Ci≤1018)P_i(1≤P_i≤10^{18}),有C_i (1≤C_i≤10^{18)}Pi(1≤Pi≤1018),有Ci(1≤Ci≤1018)头牛想吃这种糖果。 FarmerJohnFarmer JohnFarmerJohn拥有金钱BBB元(1≤B≤1
聊一聊Android中的Handler机制
前言 我们经常使用的Handler就是用来更新UI,我们知道,主线程不能执行耗时操作,这样会造成UI卡顿,所以需要在子线程进行耗时的I/0操作,文件下载或者是访问网络。我们又知道,子线程不能更新UI,当在完成子线程的耗时操作之后,就需要转换到主线程来更新UI。那么,系统是怎么样切换线程,完成子线程到主线程的转换的? 这就是本文要讲的重点,Android的消息机制。 Android的消息机制主要指的是Handler的运行机制,Handler是Android的一个上层接口,开发过程中只需要与Handler交互
Python与ArcGIS系列(二)获取地图文档
在ArcPy中,要引用当前的地图文档(Map Document),可以使用 mapping 模块中的 MapDocument 类。值得注意的是,在arcgis内部python窗口运行该代码才能访问已加载进arcgis的文档,如果通过其他idle则无法访问。要引用磁盘上的地图文档并对其进行一些设置,同样可以使用ArcPy中的 mapping 模块和 MapDocument 类。对于我们平常的工作,接触最多的就是图层数据处理,获取图层后就可以方便地进行下一步处理。
Android进程与线程基本知识
本文介绍Android平台中进程与线程的基本知识。 很早的时候就想介绍一下Android中的进程和线程,但由于其他的事情一直给耽搁了,直到现在才能和大家一起分享下。 1.Android进程基本知识: 我们先来了解下Android中的进程基本知识。 当一个程序第一次启动的时候,Android会启动一个LINUX进程和一个主线程。默认的情况下,所有该程序的...
回归预测 | MATLAB实现SVR(支持向量机回归)K折交叉验证
回归预测 | MATLAB实现SVR(支持向量机回归)K折交叉验证 目录回归预测 | MATLAB实现SVR(支持向量机回归)K折交叉验证基本介绍划分原理留一划分交叉验证K折交叉数据下载程序设计参考资料致谢 基本介绍 在机器学习里,通常来说我们不能将全部用于数据训练模型,否则我们将没有数据集对该模型进行验证,从而评估我们的模型的预测效果。为了解决这一问题,有如下常用的方法: 第一种是最简单的,也是很容易就想到的。我们可以把整个数据集分成两部分,一部分用于训练,一部分用于验证,这也就是我们经常提到的训练集
英飞凌Tricore实战系列导读
笔者结合项目应用经验对Tricore MCU的开发及应用经验进一步总结,成人达己,渡己渡人。
android finish 判断当前_踩坑之路:Activity执行finish以后onStop方法10s以后才调用
背景某天,测试提了一个bug,说当前页面关闭了以后回到了上一个页面,但是对应的音乐并没有立刻停止,而是过了一段时间才停止。于是翻阅了一下代码:@Overrideprotected void onStop() {super.onStop();if (mIsLoading) {mAudioTool.pausePlayAudio();}}mAudioTool.pausePlayAudio方法是停止播放音...
HINT: High-quality INpainting Transformer with Mask-Aware Encoding and Enhanced Attention 训练自己的数据集
HINT(高质量图像修复变换器)通过创新的掩码感知像素洗牌下采样模块(MPD)和空间激活通道注意力层(SCAL),显著提高了图像修复的质量,尤其在大面积缺失区域的情况下。实验表明,HINT在CelebA、CelebA-HQ、Places2和敦煌数据集上超越了现有的最先进模型,提升了图像的细节和结构一致性。
进程(一) 1.4Android中异步处理大杀器——Handler(3),Looper,Message,MessageQueue
介绍下handler运用中用到的相关类:Looper,Message ,MessageQueue Looper Looper类用来创建消息队列. 每个线程最多只能有一个消息队列,android中UI线程(一般指主线程)默认具有消息队列,但非UI线程在默认情况下是不具备消息队列的(这也很好的说明了,前面文章说的,只有在主线程可以直接创建handler对象,而在别的线程需要有lo
华为的C语言编程规范.pdf
华为技术有限公司内部技术规范。本规范制定了编写C语言程序的基本原则、规则和建议。从代码的清晰、简洁、可测试、安全、程序效率、可移植各个方面对C语言编程作出了具体指导。
pscad IEEE标准系统搭建说明
pscad IEEE标准系统搭建说明,包含典型的IEEE 9节点、14节点、30节点、39节点和118节点系统。内含标准测试系统的原始数据和潮流结果。
Android中Looper原理
参考: https://www.zhihu.com/question/34652589// Handler https://blog.youkuaiyun.com/rock_joker/article/details/76735333// Linux pipe/epoll https://www.cnblogs.com/coder2012/archive/2013/07/22/3204730.ht...
复分析 阿尔福斯(Ahlfors) 第三版答案 英文
答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案
android handler的使用
handler
jre9下载 jdk9
(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】
Android系统Handler详解
Handler是一套 Android 消息传递机制,主要用于线程间通信。用最简单的话描述: handler其实就是主线程在起了一个子线程,子线程运行并生成Message,Looper获取message并传递给Handler,Handler逐个获取子线程中的Message.Binder/Socket用于进程间通信,而Handler消息机制用于同进程的线程间通信可以说只要有异步线程与主线程通信的地方就一定会有 Handler。
【Android Framework系列】第1章 Handler消息传递机制
Android的Handler消息机制。
Android工程师进阶第九课 Handler机制详解
第23讲:15 分钟彻底掌握 Handler 本课时我们一起分析 Android Handler 的源码。 Handler 现在几乎是 Android 面试的必问知识点了,大多数 Android 工程师都在项目中使用过 Handler。主要场景是子线程完成耗时操作的过程中,通过 Handler 向主线程发送消息 Message,用来刷新 UI 界面。这节课我们来了解 Handler 的发送消息和处理消息的源码实现。 分析源码的时候最好是找到一个合适的切入点,Handler 源码的一个切入点就是它的默认构造器
android Handler机制简要分析
消息机制总览 如果你想要让一个 Android 应用程序反应灵敏,那么你必须防止它的 UI 线程被阻塞。同样地,将这些阻塞的或者计算密集型的任务转到工作线程去执行也会提高程序的响应灵敏性。然而,这些任务的执行结果通常需要更新UI组件的显示,但该操作只能在UI线程中去执行。有一些方法解决了 UI 线程的阻塞问题,例如阻塞队列,共享内存以及管道技术。Android 为解决这个问题,提供了一种自有的消息...
Android中Handler消息处理概述
Handler消息传递机制: Handler是Android中提供的一个消息处理机制。在任意线程中发送消息,在主线程中获取并处理消息。 进程:一个Android应用就是一个进程,每个应用在各自的进程中运行。 线程:比进程更小的独立运行的基本单位,一个进程可以包含多个线程。 在Android中线程是不安全的,子线程不允许操作主线程中的组件,可以通过Handler实现。 通过匿名内部类实例化一个Han...
Handler机制及原理探究
结合代码和实验,探究Handler的实现原理。
android学习---使用Handler
在学习Handler之前,我们先弄懂两个概念。一个是进程,一个是线程。进程就是程序运行时在内存中开辟的一个内存空间。而线程则是进程执行任务时的最小单元,分为主线程(负责更新UI)和子线程(执行耗时操作)。 一、为什么学习Handler 1.在每一个Android应用启动时,这个应用会启动一个UI线程(主线程)。2.只有在UI线程里才可以对控件、布局进行获取或设置。3.在Android设置思想中
Handler总结和补充
目录: 1 定义&作用 2 分类 3 使用:示意图,steps+code 4 使用场景 适用场景 角色作用 模块框架 消息流程 使用框架 1. 定义 一套Android消息传递机制 2. 作用 在多线程的应用场景中,将工作线程中需更新UI的操作信息 传递到UI主线程,从而实现 工作线程对UI的更新处理,最终实现异步消息的处理 why 要使用handle呢? 如果不用handle的话,子线程和主线程如何传递msg呢?自己写一个生产者-消费者模型,轮询读取msg. handle实际就是...
2万+



被折叠的 条评论
为什么被折叠?



