⑴ 为什么在 android 上启动知乎 app 时会唤醒微信
知乎调用微信sdk中分享的相关接口,微信sdk的相关接口里面,给微信发送了一个广播,微信app就被唤醒了,这不是颂盯知乎的主观行为,而是微信的(而且结合实型樱圆际的分析来看,这个应该也算是正常的功能)。
1首先说一下app的被唤醒(自启动)机制。
app自启动,基本上都是依靠Android的广播来实现的,而且是静态注册的广播(在AndroidManifest.xml文件中进行配置的广播),发送广播的方法在一般情况下是sendBroadcast。
2按照惯例,反编译一下微信apk,然后搜索卜塌一下它能够由哪些静态广播进行唤醒,同时抓取广播相关的log。
结合微信的AndroidManifest.xml文件以及抓取的log,可以知道相关的BroadcastReceiver是EntryReceiver,相关的action为
com.tencent.mm.plugin.openapi.Intent.ACTION_HANDLE_APP_REGISTER
com.tencent.mm.plugin.openapi.Intent.ACTION_HANDLE_APP_UNREGISTER
从其名称上看,是和注册/注销相关,具体接收到广播之后做了哪些处理,这些就不赘述了。
3接下来分析知乎的代码,搜索一下知乎反编译之后的smali文件(sendBroadcast),其中只有一条是和微信相关的
⑵ Android 系统运行机制 【Looper】【Choreographer】篇
目录:
1 MessageQueue next()
2 Vsync
3 Choreographer doFrame
4 input
系统是一个无限循环的模型, Android也不例外,进程被创建后就陷入了无限循环的状态
系统运行最重要的两个概念:输入,输出。
Android 中输入 输出 的往复循环都是在 looper 中消息机制驱动下完成的
looper 的循环中, messageQueue next 取消息进行处理, 处理输入事件, 进行输出, 完成和用户交互
应用生命周期内会不断 产生 message 到 messageQueue 中, 有: java层 也有 native层
其中最核心的方法就是 messageQueue 的 next 方法, 其中会先处理 java 层消息, 当 java 层没有消息时候, 会执行 nativePollOnce 来处理 native 的消息 以及监听 fd 各种事件
从硬件来看, 屏幕不会一直刷新, 屏幕的刷新只需要符合人眼的视觉停留机制
24Hz , 连续刷新每一帧, 人眼就会认为画面是流畅的
所以我们只需要配合上这个频率, 在需要更新 UI 的时候执行绘制操作
如何以这个频率进行绘制每一帧: Android 的方案是 Vsync 信号驱动。
Vsync 信号的频率就是 24Hz , 也就是每隔 16.6667 ms 发送一次 Vsync 信号提示系统合成一帧。
监听屏幕刷新来发送 Vsync 信号的能力,应用层 是做不到的, 系统是通过 jni 回调到 Choreographer 中的 Vsync 监听, 将这个重要信号从 native 传递到 java 层。
总体来说 输入事件获取 Vsync信号获取 都是先由 native 捕获事件 然后 jni 到 java 层实现业务逻辑
执行的是 messageQueue 中的关键方法: next
next 主要的逻辑分为: java 部分 和 native 部分
java 上主要是取java层的 messageQueue msg 执行, 无 msg 就 idleHandler
java层 无 msg 会执行 native 的 pollOnce@Looper
native looper 中 fd 监听封装为 requestQueue, epoll_wait 将 fd 中的事件和对应 request 封装为 response 处理, 处理的时候会调用 fd 对应的 callback 的 handleEvent
native 层 pollOnce 主要做的事情是:
vsync 信号,输入事件, 都是通过这样的机制完成的。
epoll_wait 机制 拿到的 event , 都在 response pollOnce pollInner 处理了
这里的 dispatchVsync 从 native 回到 java 层
native:
java:
收到 Vsync 信号后, Choreographer 执行 doFrame
应用层重要的工作几乎都在 doFrame 中
首先看下 doFrame 执行了什么:
UI 线程的核心工作就在这几个方法中:
上述执行 callback 的过程就对应了图片中 依次处理 input animation traversal 这几个关键过程
执行的周期是 16.6ms, 实际可能因为一些 delay 造成一些延迟、丢帧
input 事件的整体逻辑和 vsync 类似
native handleEvent ,在 NativeInputEventReceiver 中处理事件, 区分不同事件会通过 JNI
走到 java 层,WindowInputEventReceiver 然后进行分发消费
native :
java:
input事件的处理流程:
输入event deliverInputEvent
deliver的 input 事件会来到 InputStage
InputStage 是一个责任链, 会分发消费这些 InputEvent
下面以滑动一下 recyclerView 为例子, 整体逻辑如下:
vsync 信号到来, 执行 doFrame,执行到 input 阶段
touchEvent 消费, recyclerView layout 一些 ViewHolder
scroll 中 fill 结束,会执行 一个 recyclerView viewProperty 变化, 触发了invalidate
invalidate 会走硬件加速, 一直到达 ViewRootImpl , 从而将 Traversal 的 callback post choreographer执行到 traversal 阶段就会执行
ViewRootImpl 执行 performTraversal , 会根据目前是否需要重新layout , 然后执行layout, draw 等流程
整个 input 到 traversal 结束,硬件绘制后, sync 任务到 GPU , 然后合成一帧。
交给 SurfaceFlinger 来显示。
SurfaceFlinger 是系统进程, 每一个应用进程是一个 client 端, 通过 IPC 机制,client 将图像显示工作交给 SurfaceFlinger
launch 一个 app:
⑶ Android的handler机制的原理
Android的handler机制的原理分为异步通信准备,消息发送,消息循环,消息处理。
1、异步通信准备
在主线程中创建处理器对象(Looper)、消息队列对象(Message Queue)和Handler对象。
2、消息入队
工作线程通过Handler发送消息(Message) 到消息队列(Message Queue)中。
3、消息循环
消息出队: Looper循环取出消息队列(Message Queue) 中的的消息(Message)。
消息分发: Looper将取出的消息 (Message) 发送给创建该消息的处理者(Handler)。
4、消息处理
处理者(Handler) 接收处理器(Looper) 发送过来的消息(Message),根据消息(Message) 进行U操作。
handler的作用
handler是android线程之间的消息机制,主要的作用是将一个任务切换到指定的线程中去执行,(准确的说是切换到构成handler的looper所在的线程中去出处理)android系统中的一个例子就是主线程中的所有操作都是通过主线程中的handler去处理的。
Handler的运行需要底层的 messagequeue和 looper做支撑。
⑷ 安卓运行机制是什么 安卓手机的工作原理是什么
android基于Linux内核,很多系统也都基于Linux内核。但是android的特别之处除了开发上的特点以外,还有一个就是程序在运行时的行为和以往我接触到的程序运行机制有很大不同。在传统PC机或者其他一些手机上,用户对应用程序有绝对的掌控权,在应用程序的系统菜单上选择“退出”或者“关闭”之类的选项会直接杀死进程,而在android系统中不是这样的。在android中,应用程序的生命周期并不是由应用程序自身直接控制的,而是由系统,当系统需要释放内存来运行新进程或者保证某些后台进程和前端进程顺利执行的时候才会释放相应应用程序的资源,这个释放过程有一个重要性的层次。
android中进程的层次如下(重要性由高到低):
1、前端进程。顾名思义,前端进程就是目前显示在屏幕上和用户交互的进程,在系统中前端进程数量很少,而这种进程是对用户体验的影响最大,只有系统的内存稀少到不足以维持和用户的基本交互时才会销毁前端进程。因此这种进程重要性是最高的。
2、可见进程。可见进程也拥有一个可视化的界面,只是目前不是最上层界面(最上层界面在前端进程里面),可见进程一般调用了OnPause(),可见进程比前端进程重要性低,但是在交互方面影响还是很大,因为用户可能随时切换过去,所以系统不会轻易销毁它。
3、服务进程。一个服务进程就是一个Service,它调用了startService,就是UNIX中说的守护进程,对用户不可见,但是保证了一些重要的事件被监听或者维持着某些状态,比如网络数据传输、后台音乐播放,这类进程在内存不足且为了保证前端交互的顺利进行的时候被销毁。
4、后台进程。这里叫后台进程可能会和一般意义上的后台进程混淆,要说明的是,android里的后台进程是调用了OnStop()的,可以理解成用户暂时没有和这个进程交互的愿望,所以这里后台进程有点“待销毁”的意思。
5、空进程。这是一种系统缓存机制,其实就是个进程的外壳,当有新进程创建的时候,这个空进程可以加快进程创建速度,当系统内存不足的时候,首先销毁空进程。
android中进程重要性层次
⑸ Android应用自启动机制
一般应用自启动是通过差袭开机广播实现。 1.系统开机后,系统产生并发送开机广播,同时设置开机广播的Flag为FLAG_excluds_stopped_packages,即对虚档兄于之前未启动过的应用不发送开机广播。 2.系统刚开机时,检查应用之前是否启动是通过读取存储中的配置文件(package-restriction.xml)中应用的stopped属性来判断的。 3.当上一次打开应用,10秒后,系统会将蠢橘应用的stopped属性设置为false,写入配置文件。 当上一次关闭应用,10秒后,系统会将应用的stopped属性设置为true,写入配置文件。 总结:在应用打开或关闭后,系统刷新应用状态到配置文件中会有10秒的延时。
⑹ Android 性能优化 05---App启动优化
其实启动框架就是一个任务调度系统,是手淘启动的“大管家”。
管家要做的事情就是把它们的关系梳理得明明白白,有条不紊,合理安排位置、调度时间,袭哗同时提升硬件资源的利用率。
总结下来无非就是两点:
有向无环图[拓扑排序]
可用方案
APT,字节码插桩,利用ContentProvider
面试题LeakCanary 为什么不需要在Application中手动初始化?
①点击桌面App图标,Launcher进程采用Binder IPC向system_server进程发起 startActivity请求;
②system_server进程接收到请求后,向zygote进程发送创建进程的请求;
③Zygote进程fork出新的子进程,即App进程;
④App进程,通过Binder IPC向sytem_server进程发起attachApplication请求;
⑤system_server进程在收到请求后,进皮禅顷行一系列准备工作后,再通过binder IPC 向App进程发送scheleLaunchActivity请求;
⑥App进程的binder线程(ApplicationThread)在收到请求后,通过handler向主 线程发送LAUNCH_ACTIVITY消息;
⑦主线程在收到Message后,通过反射机制创建目标Activity,并回调 Activity.onCreate()等方法。
⑧到此,App便正式启动,开始进入Activity生命周期,执行完 onCreate/onStart/onResume方法,UI渲染结束后便可以看到App的主界面。
应用有三种启动状态,每种状态都会影响应用向用户显示所需的时间:冷启动、温启动与热启动。
adb命令启动应用,一般会输入三个值:ThisTime、TotalTime与WaitTime。
1.WaitTime:包括前一个应用Activitypause的时间和新应用启动的时间;
2.ThisTime:表示一连串启动Activity的最后一个Activity的启动耗时;
3.TotalTime:表示新应用启动的耗时,包括新进程的启动和Activity的启动,但不包括前一个应用Activitypause
的耗时。
StrictMode是一个开发人员工具,它可以检测出我们可能无意中做的事情,并将它们提请我们注意,以便我 们能够修复它们。 StrictMode最常用于捕获应用程序主线程上的意外磁盘或网络访问。帮助我们让磁盘和网络操作远离主线程, 可以使应用程序更加平滑、响应更快
当系统加载并启动 App 时,需要耗费相应的时间,这样会造成用户会感觉到当点击 App 图标时会有 “延迟” 现象,
为了解决这一问题,Google 的做法是燃陆在 App 创建的过程中,先展示一个空白页面,让用户体会到点击图标之后立
马就有响应。
如果你的application或activity启动的过程太慢,导致系统的BackgroundWindow没有及时被替换,就会出现启动
时白屏或黑屏的情况(取决于Theme主题是Dark还是Light)。
消除启动时的黑/白屏问题,大部分App都采用自己在Theme中设置背景图的方式来解决。
然后在Activity的onCreate方法,把Activity设置回原来的主题。
这么做,只是提高启动的用户体验。并不能做到真正的加快启动速度。
⑺ 人人都应该了解的 Android 进程管理机制
打开设置--应用与服务(不同机型进入方式可能不同),你就会看到当前正在运行的进程和服务,也就是目前正在“后台运行”的任务。列表中有你刚刚使用过的 APP ,也有一两小时前打开过的 APP。还有一些软件你甚至不知道自己什么时候打开过(其实根本就不是自己打开的),或者记得自己已经“关闭”了,但它们也在列表中,消耗着你的手机资源。列表中有一些条目名字很奇怪,一般人看不懂,但还是觉得“它很重要”,不敢轻易强悔培制关闭。这个列表展示的内容和普通的后台管理界面不太一样,感觉稍稍有些神秘,然而这又是我们日常使用所回避不了的一部分。
作为一名资深的手机用户(我相信人人都是),是时候该解决这类疑问了。这一切都要从人与宇宙的关系。。。咳咳。。手机进程的概念开始说起。
在开发文档中是这么说的:当一个应用程序启动时(仅仅只是“启动时”,并不一定有组件运行),就会产生一个进程。在这个进程中同时会创建一个主线程,使应用内的任务开始执行。Android系统总是尽可能地保留进程。举个例子,当你打开qq时,进程创建(同时创建主线程),随后各种内容加载(首先是活动,然后是各种控件什么的)。当你完成操作时,一般都会按后退键(back),直至退出程序。
这里需要注意,一般情况下我们一直按后退是希望应用程序关闭的。然而事实上这样做只是关闭了界面(活动),大多数app的“进程”仍会保留(少数良心app可以设置在退出时“完全关闭”),占用内存以进行后台任务。进程随应用启动而产生,但往往并不随着应用的“关闭”而关闭
所以很多时候我们看上去关闭了程序,但其实它仍在后台运行!(此处请自行回忆那些困扰你的流氓软件们)。不过不必担心,Android 系统自有一套进程管理机制来帮你管理后台任务。系统会根据应用的重要程度把所有进程划归为几个等级,最不重要的进程将会被优先关闭,相对重要的进程将获得资源来保留。
那么问题来了----到底如何分辨哪些进程重要而哪些不重要呢?
系统当然要保证用户体验,所以重要等级的划分原则就是要首先满足用户当前的需求:用户正在使用的当然不能关闭,而用户暂时不需要的,相对的就没那么重要了。
1.Foreground process 前台进程:也就是用户正在进行操作的进程。这样的进程优先级(优先保留)最高,最不容易销毁,因为它表现在屏幕上,直接同用户进行交互,所以只有当内存资源极度紧张等一些其他极端情猛迅况才会关闭,表现为“闪退”。我用的第一台 Android 手机运行内存(RAM)只有 290M,多任务时经常内存不足导致程序“闪退”。这手机我竟然用了两年,现在想想都佩服我自己hhhh。
不只是界面交互,如果应用程序中的服务(service)组件正在进行一些操作或者广播接收者(BroadcastReceiver)在执行接收广播的操作(onReceive)时,该进程仍被视为前台进程。
2.Visible process 可视进程:顾名思义,就是仍然在屏幕上有显示,但用户不再能直接与它交互的程序。比如当在应用中打开下滑菜单时(有些下滑菜单是透明的),用户能“看得到”,但是“摸不着”。优先级仅次于前台进程。
3.Service process 服务进程:该进程中开启了一个服务(通过startService方法)。注意这里强调的是服务的“开启”,区别于第一类中的“服务正在执行一些操作”。大多数音乐软件都是通过这种方法来保留其播放音乐的进程。
4.Background process 后台进程:当你按下 HOME 键或 BACK 键时,手机退回主界面,此时应用程序不再可见,转入后台运行。如果如果不满足前几类的条件,这个进程就会被判定为后台进程。
5.Empty process 空进程:A process that doesn't hold any active application components.没有任何组件在运行,包括活动界面(Activity)。事实上用户已经不再需要这个进程了,但出于 Android 系统“尽可能保留进程”的原则,这样的进程出现后不会被立即销毁。保留进程的唯一理由,就是为了下次开启这个应用时能快一些。其实现在的手机硬件性能足够好,这样的缓存对于用户体验的提升效果不怎么明显。这样的进程最不重要,将首先被销毁。枝前此
也许你已经注意到了,在屏幕上正在显示的或者正在服务于用户的进程的重要等级是比较高的,这是出于对用户体验的考虑-----谁会接受在自己打王者荣耀的时候游戏突然闪退呢?大多数情况下,一个应用程序的组件成分都会比较复杂,这个进程可能同时满足多个级别的划分条件。在这种情况下,它会被尽可能地划为能够达到的最重要等级。
如果你的手机上安装了好几个同一家公司推出的 APP(比如企鹅系、头条系等),那么当你启动其中之一时,剩下的几款 APP 大概率也会被唤醒(视软件的流氓程度而定)。联动开启的 APP 会大大占用内存,让手机变得卡顿。并且它们许多都需要联网服务,占用网速,有些还会在你不知情(因为你并没有直接开启或使用它们)的情况下监控你的数据并上传。
不过,你以为这就完了?
事实上,如果不手动清除,这样的进程很难被系统关闭,它们会一直长期运行。这些进程大多属于第三或第四等级,然而如果不同 APP 中的组件构成“相互依赖”的关系,它们所属进程的保留优先级就会提高,也就越不容易被关闭。(我等流氓软件可不是浪得虚名的ε=ε=ε=(  ̄▽ ̄) )
尽管 Android 想要尽可能的保存所有的进程,但是并非所有的内存都会被用于维持进程。比如系统运行会占用相当的内存,系统也需要留出一部分闲置内存用以处理新事件。Android 的管理让内存的分配处于一种“动态平衡”中,以保障各项任务都能尽可能的稳定、高效地执行。
好了,关于进程的管理就暂时说到这了。众所周知,Android 系统是一个复杂的机体,它管理着手机硬件和软件,让它们尽可能的配合,提供给用户最好的服务。这次只是简单介绍了进程管理机制,今后我也会尽量用通俗的语言从系统上去解释那些平常看上去似是而非的问题,期待你的关注!
⑻ android进程管理机制
Android系统与其他操作系统有个很不一样的地方,就是其他操作系统尽可能移除不再活动的进程,从而尽可能保证多的内存空间,而Android系统却是反其道而行之,尽可能保留进程。Android这样设计有什么优势呢?又是通过怎样的方法来管理这些被保留的进程的呢?Android用户又该如何正确使用手机从而更好发挥Android系统所特有的优势呢?本文将一一为您解开这些谜团。
本文的主要内容如下:
一、Android进程管理的特殊设计
Linux系统对进程的管理方式是一旦进程活动停止,系统就会结束该进程。尽管Android基于Linux Kernel,但在进程管理上,却采取了另外一种独特的设计:当进程活动停止时,系统并不会立刻结束它,而是会尽可能地将该进程保存在内存中,在以后的某个时间,一旦需要该进程,系统就会立即打开它,而不用再做一些初始化操作。只有当剩余内存不够用了,为了维持新开启的进程或者比较重要的进程的正常运行,系统才会选择性地杀掉一些不重要的内存,腾出内存空间来,所以Android系统永远不会有内存不足的提示。
二、Android独特进程管理设计的好处
Android这种独特的设计,也正是Android标榜的优势之一,这有两个好处:
1、最大限度地提高内存的使用率。
比如,你的内存是8G,如果每次使用完某个进程就杀掉,那么被使用的内存基本上会始终保持在某个值,比如4G以内,那么内存的使用率就总是保存在50%以内,剩余的4G内存形同虚设,发挥用处的机会非常少。而Android的这种设计,就可以做到有多少内存就用多少内存,尽可能大地提高内存使用率。同样比如有8G内存,使用完的进程仍保留在内存中,累积下来,被使用的内存就尽可能地会接近8G。
2、提高再次启动时的启动速度
被驻留在内存中不再活动的进程(后台进程或空进程,后面会再讲到),很多是经常需要使用的,当再次使用该进程的时候,系统立即打开它,而不需要再重新初始化。例如,我们常用的浏览器,当暂时不再使用时,按下Home键或Back键,浏览器进程就变成了不再活动的进程。如果下次又要使用了,点击多任务键,在最近使用应用列表中点击浏览器即可,浏览器界面仍然保持着退出前的界面。但如果退出时把该进程移除了,那么再次使用时,就需要重新初始化,然后进入该应用,这往往会花费不少的时间。
三、Android进程的五个等级
Android系统将尽量长时间地保持应用进程,但为了新建进程或运行更重要的进程,最终需要移除旧进程来回收内存。为了确定保留或终止哪些进程,系统会根据进程中正在运行的组件以及这些组件的状态,将每个进程放入“重要性层次结构”中。必要时,系统会首先消除重要性最低的进程,然后是重要性略逊的进程,以此类推,以回收系统资源。该“重要性层级结构”将进程分为了五个等级:
1、前台进程(foreground)
前台进程是指那些有组件正和用户进行交互的应用程序的进程,也称为Active进程。这些都是Android尝试通过回收其他应用程序来使其保持相应的进程。这些进程的数量非常少,只有等到最后关头才会终止这些进程,是用户最不希望终止的进程。例如:而当你运行浏览器这类应用时,它们的界面就会显示在前台,它们就属于前台进程,当你按home键回到主界面,他们就变成了后台程序。
如果一个进程满足以下任一条件,即视为前台进程:
(1)托管处于活动状态的Activity,也就是说,它们位于前台并对用户事件进行响应,此时的情形为响应了Activity中的onResume()生命周期方法,但没有响应onPause()。
(2)托管正在执行onReceive()方法处理事件程序的BroadcastReceiver。
(3)托管正在执行onStart()、onCreate()或onDestroy()事件处理程序的Service。
(4)托管正在运行且被标记为在前台运行的Service,即调用了该Service的startForeground()方法。
(5)托管某个Service,且该Service正绑定在用户正在交互的Activity的Service,即该Activity正处于活动状态。
2、可见进程(visible)
没有任何前台组件、但仍然会影响用户在屏幕上所见内容的进程。如果一个进程满足以下任一条件,即视为可见进程:
(1)托管不在前台、但仍对用户可见的Activity(已调用其onPause()方法)。例如:如果前台Acitivty启动了一个对话框,或者启动了一个非全屏,亦或是一个透明的Activity,允许在其后显示上一个Activity,则可能会发生这种情况,这类Activity不在前台运行,也不能对用户事件作出反应。
(2)托管绑定到可见Activity的Service。(官网上说是绑定到可见或前台Activity,但笔者有一点疑问,这个和“前台进程”中第(5)点相矛盾吗,绑定到前台Activity,那就是前台进程了)
可见进程被视为是极其重要的进程,这类进程的数量也很少,只有在资源极度匮乏的环境下,为保证前台进程继续执行时才会终止。
3、服务进程(Service)
正在运行已使用startService()方法启动的Serice且不属于上述两个更高类别进程的进程。尽管服务进程与用户所见内容没有直接关联,但是它们通常在执行一些用户关心的操作。因此,除非内存不足以维持所有前台进程和可见进程同时运行,否则系统会让服务进程保持运行状态。
有些资料上面也称这种进程为次要服务(Secondary Service),而属于上述两个更高类别的进程则被称为主要服务,主要服务往往属于系统进程,如拨号进程等,不可能被进程管理轻易终止。这里我们以Android开发者官网的称呼为标准,称为服务进程。
4、后台进程(hidden)
包含目前对用户不可见的Activity,即该Activity调用了onStop()方法。这些进程对用户体验没有直接影响,系统可能随时终止它们,以回收内存供上述三个更高级别的进程使用。通常会有很多后台进程在运行,它们会保存在LRU(Least Recently Used,最近最少使用)列表中,以确保包含用户最近查看的Activity的进程最后一个被终止。如果某个Activity正确实现了生命周期方法,并保存了其当前状态,则终止其进程不会对用户体验产生明显影响,因为当用户导航回该Activity时,Activity会恢复其所有可见状态。
这里读者可以做个试验,先开启微信,进入到朋友圈界面, 然后点击手机屏幕下方的导航栏中的Home按键进入到后台,再点击最近使用应用列表显示按钮(不同的手机位置不一样,有的在Home键左边,有的则在Home键右边),在显示的最近使用应用的列表中清理掉微信应用,最后再点击桌面的微信图标启动微信,会发现显示的界面仍然是朋友圈界面。
后台进程,我们可以简单理解为,应用(只考虑只有Activity组件的情况)启动后按Home键后被切换到后台的进程。如浏览器、阅读器等,当程序显示在屏幕上时,它们所运行的进程即为前台进程(foreground),一旦按home键(注意不是back键)返回到桌面,程序就停留在后台,成为后台进程。
5、空进程(empty)
不含任何活动应用组件的进程。保留这种进程的唯一目的是用作缓存,以缩短下次再其中运行组件所需要的启动时间。一般来说,当应用按back按键退出后应用后,就变成了一个空进程。比如BTE,在程序退出后,依然会在进程中驻留一个空进程,这个进程里没有任何数据在运行,作用往往是提高该程序下次的启动速度或者记录程序的一些历史信息。当系统内存不够用时,无疑,该进程是应该最先终止的。在最近使用应用列表中,可以看到按back键退出的应用。
根据进程中当前活动组件的重要程度,Android会将进程评定为它可能达到的最高级别。通俗地说,就是如果一个进程同时拥有多个对应上述不同等级进程的组件时,会以最高的那个等级作为该进程的等级。例如,如果某进程托管着服务和可见Activity,则会将此进程评定为可见进程,而不是服务进程。
此外,一个进程的级别可能会因为其他进程对它的依赖而有所提高,即服务于另一进程的进程其级别永远不会低于其所服务的进程。例如,如果进程A中的内容提供程序为进程B中的客户端提供服务,或者如果进程A中的服务绑定到进程B中的组件,则进程A始终被视为至少与进程B同样重要。
由于运行服务的进程其级别高于托管后台Activity的进程,因此启动长时间运行操作的Activity最好为该操作启动Service,而不是简单地创建工作线程,当操作有可能比Activity更加持久时更应该如此。例如,正在将图片上传到网站的Activity应该启动服务来执行上传,这样一来,即使用户退出Activity,仍可在后台继续执行上传操作。使用服务可以保证,无论Activity发生什么情况,该操作至少具备“服务进程”优先级。如果某个Activity开启了线程执行耗时操作,当Activity退出时,该Activity的实例将不会释放内存资源,直到线程执行完,这样容易导致内存泄漏。同理,广播接收器也应该使用服务,而不是简单地将耗时冗长的操作放入线程中。
四、进程移除顺序的依据——阈(yu,第四声)值
前面讲到,内存不够用时,会根据进程的等级来决定优先回收哪类进程。那么系统是根据什么来判断需要移除这些进程的时机的呢?答案是阈值。
1、查看阈值
我们可以采用如下方法查看手机中各个等级进程的阈值(需要root权限),如第二排数据所示(其单位为页):
以第一个数据44032为例,计算方法为:
1page=4KB=4*1024B=4096B
44032page* 4048B/page = 180355072B
180355072B/1024/1024 = 172M
即第一个等级的进程的阈值为172M。依次类推,阈值依次为:172M,190M,208M,226M,316M,415M。
有必要说明一下,在Android开发者官方文档中,是将Android应用进程分为了5个等级,但很多资料却是分的6个等级,在后台进程和空进程之间还有一个“内容提供节点(content provider)进程”。内容提供节点,没有实体程序,仅提供内容供别的程序去用 ,比如日历供应节点,邮件供应节点等,在终止进程时,这类进程有比较高的优先权。手机中应该是采用的6个等级的方式,如上六个数据,正好对应着六个等级的进程,等级越高,阈值越低,即前台进程阈值为172M,空进程为415M。当系统的剩余内存只剩余不到415M的时候,系统首先会回收空进程,依次类推,只有剩余内存不到172M了,才会去回收前台进程,这样就起到了优化保护重要进程的作用。
五、Home键、Back键和多任务键
Home键、Back键和多任务键,在手机屏幕的下方,这三个按键一般称为导航栏,中间的按钮为Home键,多任务键和Back键分别在其左右,一般根据手机品牌不同,左右位置也有所差异。
在运行App的时候,如果按一下Home键或者Back键,都可以退到桌面,那么这两者有什么区别呢?
Home键。按Home键的时候,App如果没有Service开启,会从一个前台进程转变为一个后台进程;如果有前台service运行,就仍然是前台进程,比如QQ音乐播放器等;如果是只有普通service运行,那么就转变为服务进程(参照前文中讲的Android进程的5个级别)。
Back键。按Back键的时候,App如果没有Service开启,会从一个前台进程转变为一个空进程;对于有Service运行的情况,和按Home键一样。
后台进程和空进程,都是驻留在后台,处于暂停状态,也都是除了占用一部分内存外,不占用其他如cpu等资源的,那么问题来了,为什么要设计后台进程和空进程这两种空进程呢?它们的区别到底在哪里呢?我们在前文讲Android进程的5个等级的时候讲到过,当剩余内存不足的时候,系统会按照等级顺序,优先移除不太重要进程,以收回内存供更重要的进程运行。那么,它们的区别就是,在剩余内存不足时,会优先移除空进程,再不足,才会移除空进程。所以,如果确实要退出某个应用一段时间内不大使用了,如果这款应用有退出按钮,就用应用自带的退出功能;如果没有,则最好按系统的Back键,这样可以变成空进程,当系统要回收内存时,就会优先被回收,从而释放的所占的资源。如果只是暂时退出去做点别的,过一会还要切换回来,或者对这款应用使用比较频繁,那就使用Home键,因为相比于按Back键,这样可以尽可能保住后台进程,方便下次使用的时候快速启动。
当然,按Home键或Back键,对用户来说,其实感觉不到差异,使用起来没什么两样,但是,对于Android开发者来说,却有必要作为常识来了解其中的道理和差异。无论是按Home键还是按Back键,在按多任务键的时候,都可以看到这些进程,如下图所示。最下面的按键为清理按键,点击后可以清除掉这些进程,回收内存了,当然,前面也讲了很多遍了,不建议这样做。
2、修改阈值。
可以采用命令:echo "44032,48640,53248,57856,80896,106241" > /sys/mole/lowmemorykiller/parameters/minfree来修改阈值,如下所示:
重启后,会恢复为原来的值。至于如何永久性修改该阈值,这里不深入探讨,有兴趣的童鞋可以自行研究,一般来说,就按照系统给定的默认值使用就可以了,没特殊用途的话,没必要修改。
对于这一节阈值的内容,暂时先讲到这里,如果要更深入,可以自行多研究研究。笔者也没有看到比较好的更深入的文章,所以也不好推荐,如果读者看到比较好的,可以推荐给笔者,感激不尽。
六、开发者选项中的进程管理功能
Android手机都带有开发者选项,隐藏了很多功能,顾名思义,这些功能主要用于辅助开发者调试程序用的。其中有一些就是关于进程管理功能的,笔者这里简单介绍一下其中两款,如下图红框部分所示:
不保留活动。用户离开以后即销毁每个活动(Activity),这样做使得后台进程都被销毁了。笔者试验过几款app,比如微信,浏览器,开启/关闭“不保留活动”前后,按Home键后,再打开应用,有明显的差别。当然,也试用了短信,DD打车,就没看出起了什么作用。读者若是感兴趣可以深入研究研究,到时候在指导指导笔者!
后台进程限制。如下图所示,给出了后台进程个数限制的选项。
七、进程管理软件的使用
Windows操作系统用户往往总想着保留更多的内存,在使用Android手机的时候,喜欢经常清理后台进程或空进程,而且清理完后,心里有一种特别爽的感觉,就像给家里做了一次大扫除一样,笔者最初使用Android手机的时候也是这样的心态-_-!基于这样的心态,一些进程清理软件,很受普通用户的青睐。其实这样做却正好抹杀了Android系统所标榜的优势,如前文所讲到的。
那么进程管理软件有无必要呢?当然有的,只是需要注意使用场合。当需要运行大型程序的时候,可以手动关闭掉一些进程,腾出足够的空间供大型程序使用,这样就可以有效避免系统调用进程调度策略而引起的卡顿,这一点,第八大点第3小节中会有说明。而且由于开发者的原因,可能是程序写得太烂,或程序容易出错,或做不该做的动作,或是恶意程序,对于这类程序进程,手动移除也是有好处的。
但如果是运行一些小程序,就完全没有必要去预先杀进程了,完全可以交给系统自己管理。读者可能会疑惑,因为小程序启动的时候,也有可能会因为内存不足而导致需要移除部分进程的情况。笔者认为,即便是内存不足,小程序运行引起的调用进程调度策略测的次数非常少,要移除的进程也非常少,产生的影响不大。同时,我们也要意识到另外一点就是,无论是手动杀死进程还是自动杀进程,都需要cpu去执行这些任务,所以也会拖慢手机和消耗电量。所以从这一点看,频繁杀进程,也是一个不好的习惯。
八、答疑解惑
在以前没有专门去了解Android进程管理机制的时候,甚至是在研究的过程中,笔者心里都经常存在很多疑惑,以下整理了其中5个,不知道读者您是否有也类似的困惑呢?
1、这么多驻留在内存的进程,不会耗电吗?
大多数用惯了Windows操作系统的童鞋,看到Android系统尽可能保留不在活动的进程的设计,可能第一反应就是质疑,难道这样不会增加耗电量吗?其实,但一个程序按home键变成后台进程或者按back键退出变成空进程后,其实已经被暂停了,只保留了运行状态,不会消耗cpu,一个程序会耗电,是因为它需要调用cpu来运算,现在不消耗cpu了,当然就不会耗电了。当然,开了service的应用就另当别论了,比如QQ音乐播放器,当按home键或back键后,音乐仍然播放,是因为它开启了服务,而且是一个前台服务,在后面我们会继续讲到,此时它是一个前台进程,而不是后台进程或空进程。
2、为什么一个不太app,运行时会占用很大的内存呢?
我们经常会碰到这样一种现象,一个只有20M的App,运行起来的时候,却会耗掉100M以上的内存。一方面是,程序运行时为对象分配内存,另一方面,是Android虚拟机的原因。Android中的应用启动的时候,系统都会给它开启一个独立的虚拟机,这样做的好处是可以避免虚拟机崩溃导致整个系统崩溃,代价就是耗用更多的内存。
3、为什么内存少的时候,运行大型程序会卡顿呢?
当剩余内存不多时,打开大型程序,系统会触发自身的进程调度策略,去移除一些等级比较低的进程来回收内存,以供大型程序运行。而这个进程调度策略在决定哪些进程需要被移除的过程,是一个十分消耗资源的操作,特别是一个程序频繁像系统申内存的时候,这样就导致了系统的卡顿。
4、应用开得太多了,手机变慢,是因为内存被占用太多吗?
其实手机变慢的根本原因是cpu被耗用太多,而不是内存占用太多,因为真正执行程序所要完成的任务的最终执行者是CPU,而不是内存(RAM)。在内存足够的情况下,如果系统中占用cpu的进程太多,那无疑cpu总有忙不过来的时候,那肯定就会变慢了。这就好比,在一条道路上驾车,道路就像内存,车的引擎就像cpu,如果车的引擎的动力不够,或者承载的货物太多,车都跑不快,即便是道路上一路畅通无阻,也无济于事。所以,内存占用多少并不重要,只要道路提供给车辆前行的空间是足够的,手机变慢的责任,就和内存无关了。这个比喻用来解释第三点也很恰当,道路提供的车辆前进的空间无法满足车辆所必需的空间时,就需要交通机制花时间来调节交通,给这辆车提供足够的空间,而在此期间,这辆车只能乖乖候着。
5、Android手机越用越慢,是什么原因呢?
Android手机常常是越用越慢,即使是恢复出厂设置,也无法改变这个现象。手机越用越慢,主要由如下几个原因:(1)虚拟机机制问题。这一点在上一个问题中也提到了,在Android4.4以前的系统,使用的是Dalvik虚拟机,它的设计机制有缺陷,就是越用越慢;在Android4.4系统中有切换按钮,可以在Art虚拟机和Dalvik虚拟机之间切换;在Android4.4以后的系统就彻底抛弃了Dalvik而全面使用Art。(2)开启了太多的服务,导致耗用太多的CPU。随着手机开机使用时间的增长,应用使用越来越多,很多应用看似退出了,而其实后台可能开了不少的服务,而他们可能还没有关闭。这些服务正在执行一些操作,会消耗CPU,而CPU才是手机变慢的根本原因。 而且Android app比较开放的,有很多不良应用充斥其中,可能对服务处理不当,滥用服务等,增加系统中的服务。(3)系统频繁调用自身的进程调度算法。这一点在前面已经说明了,这里不再赘述。(4)手机硬件的自然老化
⑼ android管理开机自启动的代码
Android开机自启动是通过BroadcastReceiver 注册开机广播来实现的
Android接收开机广播,需要用到播广播接收者BroadcastReceiver组件。
具体代码:
1.在配置文件AndroidManifest.xml中向系统注册receiver
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
2.需要添加相应权限
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
3.在Receiver中就可以添加开机需要进行的操作
public class BootCompletedReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
// 开机后执行的代码
}
}
⑽ Android的Activity代码是怎么一个运行机制。
在Android中每个界面都是一个Activity,切换界面操作其实是多个不同Activity之间的实例化操作。在Android中Activity的启动模式决定了Activity的启动运行方式。
Android总Activity的启动模式分为四种:
Activity启动模式设置:
<activity android:name=".MainActivity" android:launchMode="standard" />
Activity的四种启动模式:
1. standard
模式启动模式,每次激活Activity时都会创建Activity,并放入任务栈中。
2. singleTop
如果在任务的栈顶正好存在该Activity的实例, 就重用该实例,否者就会创建新的实例并放入栈顶(即使栈中已经存在该Activity实例,只要不在栈顶,都会创建实例)。
3. singleTask
如果在栈中已经有该Activity的实例,就重用该实例(会调用实例的onNewIntent())。重用时,会让该实例回到栈顶,因此在它上面的实例将会被移除栈。如果栈中不存在该实例,将会创建新的实例放入栈中。
4. singleInstance
在一个新栈中创建该Activity实例,并让多个应用共享改栈中的该Activity实例。一旦改模式的Activity的实例存在于某个栈中,任何应用再激活改Activity时都会重用该栈中的实例,其效果相当于多个应用程序共享一个应用,不管谁激活该Activity都会进入同一个应用中。
其中standard是系统默认的启动模式。
下面通过实例来演示standard的运行机制:
1 private TextView text_show;
2 private Button btn_mode;
3
4 @Override
5 public void onCreate(Bundle savedInstanceState) {
6 super.onCreate(savedInstanceState);
7 setContentView(R.layout.activity_main);
8
9 text_show = (TextView) this.findViewById(R.id.text_show);
10
11 text_show.setText(this.toString());
12
13 btn_mode = (Button) this.findViewById(R.id.btn_mode);
14
15 }
16
//按钮单击事件
17 public void LaunchStandard(View v){
18 startActivity(new Intent(this,MainActivity.class));
19
20 text_show.setText(this.toString());
21 }