1.android应用原理分析;
android系统与所有的系统一样都需要IPC机制去进行进程间的通信。首先我们应该先了解线程,线程是cpu最小的执行单元,同时线程是一种有限的资源,进程是一个执行单元,一个进程中可以含有多个线程。他们相互协同合作完成任务。例如:在Android中启动一个应用就会创建一个进程,进程中有一个主线程MainThread即UI线程,只有在UI线程中才能操作UI即更新UI。但是很多时候一个进程需要执行大量的耗时任务,如果任务放在主线程中就会造成程序ANR(Application No Responding)。这就是为什么一般我们都会创建一个子线程来处理耗时任务而在主线程(UI线程)更新UI。这样就会避免ANR。
Android是基于linux内核的移动操作系统,android有自己的进程间的通信方式,例如:Binder,Scoket等。android的多进程模式,一般我们可以通过android:process属性就可以开启多进程。但是这里面若应用不当会产生诸多问题。一般android默认的进程名是包名。
android系统(与linux一样)会为每一个应用创建一个UID,具有相同的UID才能运行到一个进程共享数据,在android里面我们可以通过设置shareUID在一个进程中运行。但是使用shareUID是有条件的。
1. 两个应用具有相同的UID
2. 必须具有相同的签名
在 Android 上,一个用户 ID 识别一个应用程序。应用程序在安装时被分配用户 ID,应用程序在设备上的存续期间内,用户 ID 保持不变。权限是关于允许或限制应用程序(而不是用户)访问设备资源。
Android 使用沙箱的概念来实现应用程序之间的分离和权限,以允许或拒绝一个应用程序访问设备的资源,比如说文件和目录、网络、传感器和 API。为此,Android 使用一些 Linux 实用工具(比如说进程级别的安全性、与应用程序相关的用户和组 ID,以及权限),来实现应用程序被允许执行的操作。
2.多进程的运行机制:
在一个android应用中除了拥有
此时是android的两个应用进程在运行中
Android 应用程序运行在它们自己的 Linux 进程上,并被分配一个惟一的用户 ID。默认情况下,运行在基本沙箱进程中的应用程序没有被分配权限,因而防止了此类应用程序访问系统或资源。但是 Android 应用程序可以通过应用程序的 manifest 文件请求权限。
通过做到以下两点,Android 应用程序可以允许其他应用程序访问它们的资源:
此时两个应用具有相同的UID运行在同一个进程中此时他们可以相互访问的各自的内存数据。不同的应用程序可以运行在相同的进程中。对于此方法,首先必须使用相同的私钥签署这些应用程序,然后必须使用 manifest 文件给它们分配相同的 Linux 用户 ID,这通过用相同的值/名定义 manifest 属性android:sharedUserId
来做到。
2.android的多进程机制
android应用创建时除了分配一个唯一uid之外用于区分应用,其次为android应用的每一个进程分配pid,进程中的线程分配threadid。在android中开启多进程出现的问题:
1.静态成员,与单例模式失效
2.线程同步机制失效
3.sharePreferences的可靠性下降
4.Application多次创建
(1):因为不同进程下的内存是不能共享的
所以假设我们在文件创建了一个类,类里面的静态成员在不同的进程中都会创建,但是他们的地址是不一样的,如果我们在A中改变了静态成员的值,在B中是不会显示修改前的值。
<span style="font-size:14px;">public class TestStatic { public static int num =0; } </span>
<span style="font-size:14px;">05-01 01:57:50.897 16872-16872/activity.www.goldwind.cn.firstapp:remote V/static: 0</span>单例模式是同样的原理。
(2)同样因为操作的不是同一块内存,不管是锁对象,还是锁全局都无法保证线程同步。
(3)由于SharePreferencess不支持多进程同时执行写操作,所以这样会导致数据的覆盖或丢失。所以可靠性降低
(4)Application多次创建,系统创建分配给uid后,对于每一个process相当于一个Application,系统会为其分配相应的内存空间。
我们接着做一个test
创建自定义Application
<span style="font-size:14px;">public class ApplicationDemo extends Application { @Override public void onCreate() { super.onCreate(); int i= this.getApplicationInfo().uid; Log.v("application",Integer.toString(this.hashCode())); } }</span>我们定义了两个进程我们来获取它的hashCode
<span style="font-size:14px;">05-01 02:13:27.169 30183-30183/activity.www.goldwind.cn.firstapp V/application: 1383310672</span>
<span style="font-size:14px;">05-01 02:13:38.613 30371-30371/activity.www.goldwind.cn.firstapp:remote V/application: 1383312224</span>
3.android 进程的生命周期
安卓系统试着尽可能地维护一个应用程序,但始终需要移除旧的进程来为新的或更重要的进程提供内存。为了确定哪个进程是保持和杀死的进程,系统将每个进程分“重要性层次”。
重要性等级中有五个层次。下面的列表提供了不同类型的进程,以重要性的顺序(第一个过程是最重要的。是最后一个被回收的):
1.前台进程:当前进程正在执行某些操作,如果以下条件满足则被视为前台进程。
1)该进程托管一个activity正在与用户交互。且activity的onResume()方法已经被调用。
2)该进程托管在与用户交互的activity绑定的service
3)该进程托管在运行在前台且已经调用了startForeground()方法的service
4)该进程托管存在一个广播接收者BroadcastReceiver且正在执行onReceive()方法
一般情况下,只有几个前台进程存在于以上情形。如果在内存极低无法运行这些进程时,到万不得已的时候系统会将这些进程杀掉。在这一点上,该设备已达到一个内存临界状态,因此杀死一些前景过程是必需的,以保持用户界面响应
2.可见进程:这样的进程不包含任何的前台组件,但是能对用户的可见屏幕起作用,如果符合下列条件之一则称为可见进程:
1)该进程托管一个不在前台的activity但仍然对用户可见的(其onpause()方法被调用)。这可能会出现,例如,如果前台活动开始了一个对话框,它允许以前的activity被看到。
2)他托管了一个与可见的activity绑定了的service。
一个可视化的进程被认为是非常重要的,并且不会被杀害,除非这样做是必需的,以保持所有的前台进程运行。
3.服务进程:一个进程正在运行一个服务,已开始与startservice()方法。虽然服务进程不是直接绑在任何用户看到的,他们一般都在做用户关心的事情(例如在后台播放音乐或在网络上下载数据),除非有足够的内存来保留它们以及所有的前台进程和可见的进程,因此系统会让它们运行,
4.后台进程 :一个进程拥有一个活动的当前用户不可见(活动的onstop()方法被调用)。这些过程没有直接影响用户体验,而且系统可以随时杀死他们,以回收内存供前台进程,可见进程,或服务进程使用。通常有许多后台进程在运行,所以他们被保存在一个LRU(最近最少使用算法)列表以确保与活动,最近被用户看到的过程,最后被杀。如果一个activity正确的的实现了它的生命周期方法,并且保存了当前状态,杀死它的进程不会对用户体验有直接的影响,因为当用户返回的活动,活动恢复它的所有可见的状态。查看保存和恢复状态信息的活动文档。
5.空进程:不持有任何活动应用程序组件的过程。唯一的原因,以保持这种类型的进程活着是为了缓存的目的,以提高启动时间的下一个组件需要运行在它。该系统经常会杀死这些进程,以平衡过程缓存和底层内核缓存之间的整体系统资源。
安卓是一个使进程保持在它的最高级别,它可以根据当前活动的组件的重要性来处理。例如,如果一个进程拥有一个服务和一个可见的活动,这个过程就被列为一个可视化的过程,而不是一个服务过程。其次进程的优先级是会提升的