使用手机的时候,你明明已经把这个APP关掉了,怎么过一会儿它自己又启动了,什么歌情况。特别是某些全家桶,经常是这种情况,你压根杀不掉。还有之前网上有报道某些APP会监听用户打电话,偷偷录音并上传,这些是怎么做到的。使用某些下载软件的时候,软件已经关闭,但是下载却没停止。
对于以上行为,我表示非常不赞同,所以这篇文章会告诉你上面的是怎么做到的,O(∩_∩)O哈哈~
进程优先级
不是说讲解Service么?怎么讲这个了?别急,慢慢来。开篇说了某些应用会自启动,无法杀死,而有的应用退到后台,某一段时间再次打开时,它重启了。说明这是被系统杀死的。要知道,在Android中,一般情况下一个APP的所有组件(四大组件)都是是运行在一个进程中的,所以系统杀死的就是这个进程,进程被干掉了,APP也就没了。系统杀死进程的原因是因为系统的内存资源比较紧张,系统需要为一些急需内存资源的组件去提供足够的内存资源,所以系统就把一些进程杀死了。
这里说的一般情况下一个APP的所有组件都是是运行在一个进程中的言外之意指的是,你可以指定某些组件运行在指定的进程中的。可以在清单文件中进行android:process 设置指定的进程名称。
当然也可以给整个组件设置统一的进程,这个也是在清单文件中配置。在<application>这个节点设置android:process属性就可以了。
那么,什么情况下要去杀死进程呢?依靠什么来杀死某些进程,这就涉及到进程的优先级。Android系统在内存不够充足的情况下杀死进程优先级较低的进程。Android中将进程的优先级分为5个层级(相当于5中类型的进程),主要依据对于用户的需求程度来判断的。
优先级分类(从上到下进程优先级越来越低)
英文文档在“sdk/docs/guide/components/processes-and-threads.html”
- 前台进程
- 可见进程
- 服务进程
- 后台进程
- 空进程
下面一个一个来讲:前台进程
前台进程有很多种情况,如果一个进程属于下面的任意一种情景,都属于前台进程。
- 情景一:该进程中有Activity的onResume被调用,此时用户正与这个Activity交互。
- 情景二:该进程中有一个Service,该Service绑定到当前正在与用户交互的Activity。
- 情景三:该进程中的通过startForegrount()启动的Service。
- 情景四:该进程中的Service正在执行onCreate()、onStart()、onDestory()。
- 情景五:该进程中有正在执行onReceiver()的BroadcastReceiver。
分析前台进程
- 情景一:对于这种情况没什么好说的,用户正在与当前的Activity进行交互呢,不到万不得已,不能杀死。
- 情景二:现在先不讲,下面讲解过service后再来补充
- 情景三:对于startForegrount()启动的服务是十分重要的,这种启动的服务,就下面这种的:
后面我会告诉大家这种需求是如何实现的,慢慢来,不急。
很明显,对于这种前台进程,我们几乎不会见到被消失(被杀死),他是一只常驻内存的,一直都是运行在前台的服务。
- 情景四:一样,现在先不讲,下面讲解过service后再来补充
- 情景五:假设你已经学过了BroadcastReceiver,就知道他的方法onReceiver(),当收到广播时,系统就要进行相应的onReceiver中的操作。我好不容易收到一条广播,现在就要处理广播中的事情,你却要把我干掉,我不服。所以对于这种情景的进程是十分重要的,是会影响用户的直观体验的,这个必须提升为前台进程。
总结:以上几种情景的前台进程只有在内存严重不足的情况下不到万不得已才会被系统杀死,杀死的目的是为了及时响应系统级别的需求,使得用户界面不会出问题。
可见进程
可见进程指**没有任何前台组件、但仍会影响用户在屏幕上所见内容的进程。 **
百度百科说:
可见(来自百度百科)意思指:君子以成熟的德行为表率,时间久了就能看到他的这种行为。
无论是古文还是现代文,“可见”,有点朦胧的感觉,就像你跟她之间隔了一个玻璃一样。虽然就在你眼前,可我却触碰不到你,(o)/~。
这里的可见进程有两种,但都是透露了一种朦胧感觉情况下的进程:
- 情景一:该进程的service绑定到了可见或者在前台的Activity。
- 情景二:当前进程中有Activity,但是不在不在前台,却可以看见。
分析
- 情景一:(后面讲解service时再讲)
- 情景二:靠,情景二什么情况?下面我就演示下:
两个APP两个进程,分别对应A、B。打开A后再打开BAPP,特殊之处在与B APP的Activity是透明的。
APP B的清单文件:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.asia.app_b">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@android:style/Theme.Translucent"> //设置APP B的Activity为透明的
<activity android:name=".MainActivity" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
APP A中添加打开APP B的方法
APP A的MainActivity文件如下,主要添加了显示变化的时间的功能。
MainActivity.class onResume下的可见进程打开APP B 后,此时APP B是前台进程,前台组件是APP B的所有组件。APP A 进入了Pause状态,可见但是没有获取焦点。此时APP A是可见进程,APP A没有任何前台组件、但仍会影响用户在屏幕上所见内容的。对于用户来说,依然想看到APP A上的时间变化,对用户来说APP A的进程重要性仅次于APP B,也就是仅次于前台进程。
可见进程也是十分重要的进程,除非维持所有前台进程运行时有危险时,系统才会干掉可见进程。
总结可见进程:没有任何前台组件、但仍会影响用户在屏幕上所见内容的进程。
服务进程
这个就是这篇文章的高潮,讲解Service的内容。该进程中有通过startService启动的服务,同时该服务的情况不属于前台进程以及可见进程。 服务进程的重要性仅次于前台进程和可见进程。这句话看起来是废话,其实不然,因为他后面还有两个进程。对于服务进程而言,虽然他不会直接对用户所关心的界面造成影响,但是有的时候做文件下载或者后台播放音乐,是需要在这个进程中进行的。
可能有人问,下载文件我直接在Activity中开启子线程不就可以了么?为什么需要在服务中进行下载呢?
我们先在Activity中开启一个主线程进行模拟下载。
开始下载的时候一切正常,然后按下返回键,activity被销毁,此时APP A在空进程(进程的一种)中,下载继续。模拟内存不够充足,我清空了后台运行的APP A,此时下载停止了。很明显的,下载文件不能因为我清空了后台运行的APP就将下载停止了。谷歌提供的解决方案就是在服务进程中进行下载操作。这种进程不会被轻易杀死。
注意:
开启一个服务,并不会直接开启一个新的进程(除非你指定了新的进程),也不会开启一个新的子线程。服务也是运行在主线程中的,所以如果需要在服务中进行耗时操作,需要在服务中开启一个子线程去下载文件。
杀死服务进程的可能性也较低,除非内存不足以支撑前台进程、可见进程的运行。
总结服务进程: 该进程中有通过startService启动的服务,同时该服务的情况不属于前台进程以及可见进程。
后台进程
该进程包含对用户不可见的Activity进程(该Activity的onStop方法被调用)
分析后台进程
这种进程不知道什么时候就会被系统干掉了,因为这下进程不会直接影响用户的直观体验,回收的目的为了供前台进程、可见进程、服务进程使用。
在手机中会有很多这种进程,他们都被缓存在一个列表中。这个列表就是LRU列表。然后根据LRU(Least Recently Used 近期最少使用算法),将很久以前使用的进程第一个杀掉,最后杀掉刚刚进入后台的进程,保证刚刚最近被使用的进程快速还原。
当你把APP退到后台,过一段时间再打开式,只要从引导页进入,说明这个进程处于后台进程的时候被干了。。。
空进程
没有处于活动状态的任何组件所在的进程。
分析空进程
刚才在服务进程中讲的在Activity中开启子线程下载文件,退出APP后,该进程就变成了空进程。之所以保留这种进程,是为了下载快速启动该进程。这种进程经常被干掉。
此篇最后
Android中的五种进程,前台进程、可见进程、服务进程、后台进程、空进程。基本讲完了,其中涉及到Service的在下篇文章中会引入。
有什么问题,不吝赐教O(∩_∩)O哈哈~
网友评论