[这篇文章是我对dev Guide中Processes and Threads的翻译和总结, 也加上了一些个人理解]
android中的进程
默认情况下, 同一个application中的所有component运行在同一个linux进程下. 启动一个component A时, 如果已存在处于运行状态中的component B, 且A和B属于同一个application, 那么component A将在component B所在的进程下运行. 否则将为A创建一个新的linux进程.
开发者也可以为application中的component指定不同的运行进程. manifest.xml文件中的<activity>, <service>, <receiver>, <provider>标签都支持android:process属性, 通过这个属性, 可以为component指定运行的进程. <application>标签也支持设定android:process属性, 用于为application下的所有component指定默认的运行进程.
进程优先级
当系统的内存不足时, android系统将根据进程优先级选择杀死一些不太重要的进程. 进程优先级从高到低分别为:
1. 前台进程. 以下的进程为前台进程:
a. 进程中包含处于前台的正与用户交互的activity;
b. 进程中包含与前台activity绑定的service;
c. 进程中包含调用了startForeground()方法的service;
d. 进程中包含正在执行onCreate(), onStart(), 或onDestroy()方法的service;
e. 进程中包含正在执行onReceive()方法的BroadcastReceiver.
系统中前台进程的数量很少, 前台进程几乎不会被杀死. 只有当内存低到无法保证所有的前台进程同时运行时才会选择杀死某个前台进程.
2. 可视进程. 以下进程为可视进程:
a. 进程中包含未处于前台但仍然可见的activity(调用了activity的onPause()方法, 但没有调用onStop()方法). 典型的情况是运行activity时弹出对话框, 此时的activity虽然不是前台activity, 但其仍然可见.
b. 进程中包含与可见activity绑定的service.
可视进程不会被系统杀死, 除非为了保证前台进程的运行而不得已为之.
3. 服务进程. 进程中包含已启动的service.
4. 后台进程. 进程中包含不可见的activity(onStop()方法调用后的activity). 后台进程不会直接影响用户体验, 为了保证前台进程/可视进程/服务进程的运行, 系统随时都有可能杀死一个后台进程. 一个正确的实现了生命周期方法的activity处于后台时被系统杀死, 可以在用户重新启动它时恢复之前的运行状态.
5. 空进程. 不包含任何处于活动状态的进程是一个空进程. 系统经常杀死空进程, 这不会造成任何影响. 空进程存在的唯一理由是为了缓存一些启动数据, 以便下次可以更快的启动.
进程优先级的额外说明
1. 系统会赋予进程尽可能高的优先级. 例如一个进程既包含已启动的service, 也包含前台activity, 则这个进程会被视为前台进程.
2. 由于组件之间的依赖性, 进程的优先级有可能被提高. 假如进程A服务于进程B, 则进程A的优先级不能低于进程B. 比如, 进程A的ContentProvider组件正在服务于进程B的某个组件, 或者进程A的service组件和进程B的某个组件绑定等, 这些情况下, 进程A的优先级都不会低于进程B(如果按照优先级规则, 进程A的优先级确实低于进程B, 则系统会选择提高进程A的优先级到和进程B相同).
3. 由于服务进程的优先级高于后台进程, 因此如果activity需要执行耗时操作, 最好还是启动一个service来完成. 当然, 在activity中启动子线程完成耗时操作也可以, 但是这样做的缺点在于, 一旦activity不再可见, activity所在的进程成为后台进程, 而内存不足时后台进程随时都有可能被系统杀死(但是启动service完成耗时操作会带来数据交互的问题, 比如耗时操作需要实时更新UI控件的状态的话, service就不是一个好的选择). 基于同样的考虑, 在BroadcastReceiver中也不应该执行耗时操作, 而应该启动service来完成(当然, BroadcastReceiver的生命周期过于短暂, 也决定了不能在其中执行耗时操作).
android中的线程
系统不会为进程中的每一个组件启动一个新的线程, 进程中的所有组件都在UI线程中实例化. 关于android中的多线程机制, 请参考我的另一篇博文http://coolxing.iteye.com/blog/1208371
永远要记得:
1. 不要阻塞UI线程. 如果在UI线程中执行阻塞或者耗时操作会导致UI线程无法响应用户请求.
2. 不能在非UI线程(也称为工作线程)中更新UI, 这是因为android的UI控件都是线程不安全的.
由上所述, 开发者经常会启动工作线程完成耗时操作或阻塞操作, 如果需要在工作线程的执行期间更新UI状态, 则应该通知UI线程来进行.
线程间通信
请看下面的代码:
public void onClick(View v) {
new Thread(new Runnable() {
public void run() {
Bitmap b = loadImageFromNetwork("http://example.com/image.png");
mImageView.setImageBitmap(b);
}
}).start();
}
上面的代码是错误的, mImageView.setImageBitmap(b)违反了第二条准则--不能在工作线程中更新UI.
线程间通信可以解决工作线程如何通知UI线程更新控件的问题. android提供了3种线程间通信的方案:
1. 调用以下方法:
Activity.runOnUiThread(Runnable)
View.post(Runnable)
View.postDelayed(Runnable, long)
如果在工作线程中调用了这3个方法, 那么方法中Runnable参数封装的操作会在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() {
// run方法会在UI线程中执行
public void run() {
mImageView.setImageBitmap(bitmap);
}
});
}
}).start();
}
2. Handler机制. Handler机制允许开发者在工作线程中调用与UI线程绑定的handler对象的sendMessage()方法向UI线程的消息队列发送一条消息, UI线程会在适当的时候从消息队列中取出消息并完成处理.
3. 使用AsyncTask类. 创建一个AsyncTask类的子类, 并根据需要选择覆写onPreExecute(), doInBackground(), onProgressUpdate(), onPostExecute()方法.AsyncTask类的具体使用方法请参看文档, 以下是一些大概的说明:
a. AsyncTask类是一个泛型类, 存在3个泛型参数. 第一个参数指定execute方法的参数类型, 第二个参数指定onProgressUpdate()方法的参数类型, 第三个参数指定 doInBackground()方法的返回值类型以及onPostExecute()方法的参数类型.
b. 执行流程: 在UI线程中调用AsyncTask类的execute方法(只有该步骤是由程序员控制的)-->系统调用onPreExecute(), 这个方法在UI线程中执行-->系统调用doInBackground()方法, 这个方法在工作线程中执行-->在doInBackground()方法中每调用一次publishProgress()方法, 就会在UI线程中执行一次onProgressUpdate()方法-->doInBackground()方法执行完成后, 系统将调用 onPostExecute()方法, 并将doInBackground()方法的返回值传递给 onPostExecute()方法的形参. onPostExecute()方法在UI线程中执行.
采用这种方式也可以修正例子中的错误之处:
public void onClick(View v) {
new DownloadImageTask().execute("http://example.com/image.png");
}
private class DownloadImageTask extends AsyncTask<String, Void, Bitmap> {
protected Bitmap doInBackground(String... urls) {
return loadImageFromNetwork(urls[0]);
}
protected void onPostExecute(Bitmap result) {
mImageView.setImageBitmap(result);
}
}
分享到:
相关推荐
这篇博客“android笔记--Service与AIDL”深入探讨了这两者在Android开发中的应用。 Service的基本概念: 1. Service是一种轻量级的后台组件,它可以持续运行,即使用户已经离开了应用程序。Service并不运行在单独的...
【Android学习笔记--Binder】 Binder是Android系统中的核心组件,它是Android系统实现进程间通信(IPC,Inter-Process Communication)的主要方式。Binder机制允许不同进程的组件之间进行数据交换和功能调用,就像...
其次,笔记深入讲解了Android应用程序的生命周期管理,包括Activity、Service、BroadcastReceiver和ContentProvider的创建与使用。这部分内容对于理解和控制应用的行为至关重要,能确保你的程序在不同场景下运行稳定...
Android开发教程及笔记,基础用法,Activity和任务,进程和线程
- Android进程的定义以及进程优先级的介绍。 8. Android消息提示 - Toast消息提示:系统提示信息,显示短暂。 - Notification消息提示:系统通知栏显示通知。 9. Android资源管理 - 不同类型的资源文件管理,...
《Android群英传笔记》是一份详尽的关于Android开发的学习资料,涵盖了Android开发的核心概念、关键技术和实战应用。这份笔记旨在帮助开发者深入理解Android系统的工作原理,掌握开发技巧,并能应用于实际项目中。 ...
需要注意的是,由于`onReceive()`的生命周期短暂,创建新线程进行耗时操作可能会导致线程未执行完BroadcastReceiver就已销毁。另外,在内存紧张时,系统会优先结束不包含任何活动组件的进程,这可能导致由...
Android开发笔记,内容涉及模拟器参数、进程与线程、Android 释放手机资源,进程释放优先级、分析HelloAndroid、添加编辑框与按钮、使用Intent启动另一个Activity、在不同Task中启动Activity、Intent与Intent ...
包括环境搭建教程、创建模拟器、新建helloworld程序、电话拨号器、软件部署到模拟器、短信发送器、线性布局、相对布局、日志、activity、Android进程线程及优先级、Android UI线程阻塞及优化、广播接受者、Service...
这份“Android详细笔记”涵盖了从基础到进阶的各种知识点,旨在帮助读者深入理解Android开发技术。 一、Android系统架构 Android系统由五层结构组成:Linux内核、硬件抽象层、系统运行库、应用程序框架以及应用程序...
一、Android笔记部分 这部分内容可能涵盖了以下几个关键知识点: 1. **环境搭建**:讲解如何安装Android Studio,配置Java环境,以及设置Android SDK和AVD管理器。 2. **基本概念**:介绍Android系统的架构,包括...
5. **Activity与Fragment**:Activity是Android应用的基本单元,而Fragment则用于构建多屏兼容的应用。 6. **Intent**:Intent是Android中用来启动一个操作或者传递数据的关键机制,是应用组件间通信的主要方式。 ...
- **DDMS**:Dalvik Debug Monitor Service,是Android的调试工具,提供了查看内存、线程、堆栈信息等功能,帮助开发者定位和解决问题。 - 工作原理:DDMS基于Eclipse,提供了实时的设备和应用程序监控。 - ...
Android 的基本概念包括 Android 的架构、Android 的组件、Android 的进程和线程等。Android 的版本信息包括 Android 的主分支和 Android 的分支。 在安装和配置 Android 开发环境时,需要安装 JDK、Eclipse IDE、...
Android学习入门笔记主要涵盖了一系列关于Android开发的基础知识,旨在帮助初学者快速掌握这一全球最流行的移动操作系统之一的编程技能。以下是一些核心知识点的详细解释: 1. **Android概述**: - Android是由...
### Android学习笔记知识点详解 #### 一、Android简介与历史 - **定义**: Android是由Google公司主导开发的一款基于Linux内核的操作系统,主要用于移动设备,如智能手机和平板电脑。 - **发展历史**: Android项目...