im即时通讯开发应用保活之进程防杀

2022/6/25 5:19:37

本文主要是介绍im即时通讯开发应用保活之进程防杀,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

在Android 4.4及以后的系统中,应用能否常驻内存,一直以来都是相当头疼的事情,尤其移动端IM、消息推送这类应用,为了保证“全时在线”的概念,真是费尽了心思。虽然APP常驻内存对于用户来说比较”恶心”,但是在诸如IM和消息推送这类场景来说,APP的常驻内存却尤其重要。

于是,又带着怀疑的眼光,重新找回原来的代码进行测试,顺便分析了市场上主流运动类APP保活方法(微信、手Q就算了,富人家的孩子,不具代表性),同时也对系统对内存中APP的管理规则进行了进一步探索。

Andriod应用保活核心思想归纳

对于Android6.0及其以上系统APP保活,我觉得主要还是通过这两个方面进行,即:

    降低omm_adj值,尽量保证进程不被系统杀死(本文要讨论的内容);

    进程被杀死后,通过其他方式将进程复活(将在下篇讨论)。

但需要明白的是,面对各手机厂商的深度定制和谷歌越来越严格的资源管理机制,这两种方式结合的保活不是永久的,只能是相对存在,不同的机型结果也是不一样的。

由于篇幅限制,本文主要剖析下通过何种方式降低oom_adj的值来降低APP被杀的几率,以及oom_adj值是怎样做到的?

 

接下来,我们需要了解下Android系统回收内存中的进程所依据的规则:

进程在内存中时活动主要有五种状态:即前台进程、可见进程、服务进程、后台进程、空进程,这几种状态的进程优先级由高到低,oom_adj值由低到高(在ProcessList定义)。然后Android系统会根据当前系统资源和进程oom_adj值来回收相应的进程,前台进程一般不会被回收,空进程最容易被回收,这种管理规则就是"传说中"的Low Memory Killer。

注:优先级1表示最高级,普通进程的oom_adj>=0,系统进程oom_adj<0,系统会根据相应的内存阀值对符合某段oom_adj值的进程进行回收。另外,oom_adj值也会随着占用物理内存越大而增大,系统进程绝对不会被系统杀死。

接下来我将首先分析市面上的主流APP防杀方式,为我接下来的方案提供参考依据,请继续往下阅读

APP进程防杀方案第一阶:开启前台Service,“逼君上位”

将Service置为前台,目的时提高进程Service的oom_adj值,以降低其被系统回收的几率。该方案的原理是,通过使用 startForeground()方法将当前Service置于前台来提高Service的优先级。需要注意的是,对API大于18而言 startForeground()方法需要弹出一个可见通知,如果你觉得不爽,可以开启另一个Service将通知栏移除,其oom_adj值还是没变的。

讲解一下,这里还用到了两个技巧:

    一是在onStartCommand方法中返回START_STICKY,其作用是当Service进程被kill后,系统会尝试重新创建这个Service,且会保留Service的状态为开始状态,但不保留传递的Intent对象,onStartCommand方法一定会被重新调用;

    其二在onDestory方法中重新启动自己,也就是说,只要Service在被销毁时走到了onDestory这里我们就重新启动它。

讲解一下:

从所周知,一个Service没有自己独立的进程,它一般是作为一个线程运行于它所在的应用进程中,且应用进程名称与包名一致。如果希望指定的组件和应用运行在指定的进程中,就需要通过android:process属性来为其创建一个进程,因此android:process=":daemon_service"就是让DaemonService运行在名为“com.jiangdg.keepappalive:daemon_service”进程中;android:enabled属性的作用是Android系统是否实例化应用程序中的组件;android:exported属性的作用是当前组件(Service)是否可以被包含本身以外的应用中的组件启动。

测试结果:

接下来,我们观察下KeepAppAlive进程的oom_adj值变化。

首先,adb查看KeepAppAlive进程的进程号:

E:\Android\StudioProject\KeepAppAlive>adb shell

shell@trltechn:/ $ su

root@trltechn:/ # ps | grep jiangdg

APP进程防杀方案第二阶:监听锁屏广播,“制造‘1像素’惨案”

讲解一下:

Java中为对象的引用分了四个级别:强引用、软引用、弱引用、虚引用。这里,我们使用了弱引用WeakReference来防止内存泄漏,为了解释这个问题,我们举这么一个例子:有两个类class A和class B,分别实例化这两个类得到a,b,其中a又作为实例化B时传入的构造参数,代码如下:

A a = newA();

B b = newB(a);

从这两行代码来看,a是对象A的引用,b是对象B的引用,对象B同时依赖于对象A,对象A和对象B之间形成了强引用。当a=null时,a不在指向对象A,通常情况下,对象A在不被其他对象引用时会被GC回收,但是由于B还依赖于对象A,对象A不会被GC回收,从而造成内存泄漏(除非b=null,对象A和对象B才会被GC同时回收)。如果使用弱引用的话,对象A只会被WeakReference所依赖,当a=null时,GC会回收它,从而避免了内存泄漏。即时通讯开发

 

在UI界面架构中,每个Activity都包含一个Window对象,在Android中Window对象通常由PhoneWindow来实现,PhoneWindow将一个DecorView设置为整个应用窗口的根View,它作为窗口界面的顶层视图,封装了很多通用操作窗口的方法...好了,不扯远了,既然我们已经知道Window对象在一个Activity中的位置,这里我们通过getWindow方法来获得SinglePixelActivity的Window对象,然后为其设置相关属性,比如窗体的大小、位置、坐标等,来达到所需的"1像素"界面效果。

讲解一下:

1)android:launchMode属性:用于指定activity的启动模式,总共分为四种,即:

- standar模式,每次启动activity都会创建其实例,并加入到任务栈的栈顶;

- singleTop模式,每次启动activity如果栈顶时该activity则无需创建,其余情况都要创建该activity的实例;

- singleTask模式,如果被启动的activity的实例存在栈中,则不需要创建,只需要把此activity加入到栈顶,并把该activity以上的activity实例全部pop;

- singleInstance模式:将创建的activity实例放入单独的栈中,该栈只能存储这个实例,且是作为共享实例存在。

2)android:configChanges属性:用于捕获手机状态的改变,即当手机状态(如切换横竖屏、屏幕大小)改变时会保存当前活动状态重启Activity,由于SinglePixelActivity肩负着保活的特殊使命,这里使用android:configChanges属性:防止Activity重启,它只是调用了onConfigurationChanged(Configuration newConfig)来通知手机状态的改变;

3)android:excludeFromRecents属性:用于控制SinglePixelActivity不在最近任务列表中显示;

4)android:finishOnTaskLaunch属性:用于标记当用户再起启动应用(TASK)时是否关闭已经存在的Activity的实例,false表示不关闭;

5)android:theme属性:用于指定Activity显示主题,这里我们自定义主题SingleActivityStyle。

监听锁屏广播,锁屏时将SportActivity置于前台(可见) :

监听锁屏广播,锁屏时开启SinglePixelActivity(1像素):

APP进程防杀方案第三阶:循环播放一段无声音频,"打造金刚不坏之身"

对于三星C9、Note4和华为4X来说,结合前台Service和悬浮界面(1像素)的保活方式,在用户不主动清理或强杀的情况下,测试APP的保活效果还是非常不错的。

但是,对于华为Mate8来说,效果还是差强人意,尤其是当使用一键清理内存时,测试APP基本无法幸存。然后,"咕咚"却奇妙的活了下来,一键清理怎么也清不掉,正当自己百思不得其"姐"时,一个"恶心"的界面出现在我面前。尼玛!看到下面的红框框没,"咕咚"居然在后台循环播放一个无声音乐,难怪生命力这么旺盛,但是耗电也是杠杠的。

好吧,不纠结这么多,这里只是从学技术的角度出发而研究,毕竟用户对耗电量还是很敏感的,不到万不得已还是收敛点,不要这么"风骚",用户体验很重要,一不小心就"泻"了你。

测试结果:

这里在cmd窗口使用"ps | grep jiangdg"命令,如果进程在内存中存在,则打印进程信息;如果不存在,则没有信息。

各机型测试情况如下:

1)华为Mate8(Android 7.0):将测试APP置于后台,前台Service在黑屏状态下1分钟之内被干掉,"1像素"悬浮Activity在黑屏状态下测试2小时依然存活,效果还可以。但是,当用户一键清理最近应用时,会被杀死,当在后台开启Serive循环播放一段无声音频时,一键清理依然存活,在置于后台的黑屏模式下存活12小时以上;

2)三星C9(Android 6.0):开启前台Service和1像素,KeepAppAlive在黑屏后台模式下存活9个小时以上,看样子原生系统还是温柔些;开启后台播放音频服务,用户一键清理最近应用成功保活;

3)华为4X(Android 6.0):效果同C9;

4)三星Note4(Android 5.0):效果同C9。

注:Mate8循环播放一段无声音频,当用户点击一键清理最近应用时,KeepAppAlive不会被干掉,但是如果用户只选择清理KeepAppAlive时,也会被杀死,这与"咕咚"保活效果一致。

 





这篇关于im即时通讯开发应用保活之进程防杀的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程