前言

遥想当年,博主铭记在心的一件事,就是曾做过让我加快秃顶的功能——健步活动。我们知道,在Android4.4之后的版本中,Android在硬件中支持内置计步传感器,例如微信运动等软件都是调用了Android中的Sensor.TYPE_STEP_COUNTER传感器服务,从而获取到每日的步数。

由于当时用户手机版本普遍偏低,因此需要手写记步。当时好在机智如我,参考了微信摇一摇的原理,通过加速度传感器SENSOR_TYPE_LINEAR_ACCELERATION获取到在某个时间段的加速度值,最后通过一顿计算公式得出步数。但是不同机型的加速度值并不相同,而且超级耗电。而最难的问题,就是应用特别容易被杀死,因为内存和电量耗损大,当应用在后台运行会优先被系统回收,而且用户手动一键清理时杀死进程,导致无法记步。

一、常见的应用保活方法

1、  监听广播方式

通过监听全局的静态广播,如开机广播、解锁屏广播、网络状态广播等,来启动应用的后台服务。目前,在高版本的Android系统中已经失效,因为Android系统规定应用必须在系统开机后运行一次才能监听这些系统广播,一般应用进程被杀死,广播也接收不到。

2、 提高Service的优先级

提高Service优先级方法很多,比如onStartCommand返回START_STICKY使系统内存足够的时候Service能够自动启动、弹出通知、配置service的优先级等,这些方式只能在一定程度上缓解service被立马回收,但只要用户一键清理或者系统回收照样无效。

3、 双service拉起

经过测试,只要当前应用被杀,任何后台service都无法运行,也无法拉起。

4、双进程拉起

这种方式使用NDK在底层fork出一个子进程,来实现与父进程之间的互拉。在Android4.x还是非常有效的,但是高版本的Android系统的系统回收策略已经改成进程组的形式了,如果系统要回收一个应用,必然会杀死同属于一个进程组的所有进程导致双进程无法拉起。

 5、Wake_Lock

系统为了节省电量,CPU在没有任务忙的时候就会自动进入休眠,有任务需要唤醒CPU高效执行的时候,就会给CPU加Wake_Lock锁。

Wake Lock是Android框架层提供的一套锁的机制,应用使用该机制可以达到控制系统无法进入休眠,cpu的保持运行。意思就是我的程序给CPU加了这个锁那系统就不会休眠了,这样做的目的是为了全力配合我们程序的运行。

当手机灭屏状态下保持一段时间后,系统会进入休眠,一些后台运行的任务就可能得不到正常执行,比如网络下载中断,后台播放音乐暂停,再比如微信等及时通讯的心跳包会在熄屏不久后停止网络访问等问题。WakeLock正是为了解决这类问题,应用只要申请了WakeLock,那么在释放WakeLock之前,系统不会进入休眠,即使在灭屏的状态下,应用要执行的任务依旧不会被系统打断。所以微信里面是有大量使用到了Wake_Lock锁。

但是用wake唤醒CPU持续来工作是会造成耗电的,记得在合适的业务情况下释放Wake_Lock。

二、多进程音频保活方案

综上所述,上面的方法只是提高了APP后台运行存留能力,在用户不主动清理或强杀的情况下,测试APP的保活效果还是非常不错的。但是,"咕咚"在点击一键清理时奇妙的活了下来,原因是在后台循环播放一段无声音乐。如下图:

代码如下:

public class PlayerMusicService extends Service {private final static String TAG = "PlayerMusicService";private MediaPlayer mMediaPlayer;@Nullable@Overridepublic IBinder onBind(Intent intent) {return null;}@Overridepublic void onCreate() {super.onCreate();mMediaPlayer = MediaPlayer.create(getApplicationContext(), R.raw.silent);mMediaPlayer.setLooping(true);}@Overridepublic int onStartCommand(Intent intent, int flags, int startId) {new Thread(new Runnable() {@Overridepublic void run() {startPlayMusic();}}).start();return START_STICKY;//注释1}private void startPlayMusic(){if(mMediaPlayer != null){mMediaPlayer.start();}}private void stopPlayMusic(){if(mMediaPlayer != null){mMediaPlayer.stop();}}@Overridepublic void onDestroy() {super.onDestroy();stopPlayMusic();// 注释2Intent intent = new Intent(getApplicationContext(),PlayerMusicService.class);startService(intent);}
}

AndroidManifest.xml

<service android:name=".service.PlayerMusicService"android:enabled="true"android:exported="true"android:process=":music_service"/>//多进程

注释1:在onStartCommand方法中返回START_STICKY,其作用是当Service进程被kill后,系统会尝试重新创建这个Service。

注释2:在onDestory方法中重新启动自己,即Service被销毁时调用onDestory,就执行重新启动代码。

开启后台播放音频服务,此方案在各机型测试情况如下:
1、 华为Mate8(7.0) ,一键清理依然存活,在置于后台的黑屏模式下存活12小时以上;但是如果用户只选择清理此应用也会被杀死,这与"咕咚"保活效果一致。
2、三星C9(6.0),一键清理最近应用,成功保活;
3、华为4X(6.0):一键清理最近应用,成功保活;
4、三星Note4(5.0):一键清理最近应用,成功保活;

三、通过JobScheduler方案

概述

JobScheduler是谷歌在Android 5.0引入的一个能够执行特定任务的API,当条件满足时执行指定的任务。通常情况下,即使APP被强制停止,预定的任务仍然会被执行。

原理

在重写父类JobService的onStartJob的方法中执行任务,使用JobInfo的Builder方法来设定条件并和实现了JobService的子类的组件名绑定,然后调用系统服务JobScheduler的schedule方法。这样,即便在执行任务之前应用程序进程被杀,也不会导致任务不会执行,因为系统服务JobScheduler会使用bindServiceAsUser的方法把实现了JobService的子类服务启动起来,并执行它的onStartJob方法

新建类:AliveJobService.java

@TargetApi(21)
public class AliveJobService extends JobService {private static final int MESSAGE_ID_TASK = 0x01;// 告知编译器,这个变量不能被优化private volatile static Service mKeepAliveService = null;public static boolean isJobServiceAlive(){return mKeepAliveService != null;}private Handler mHandler = new Handler(new Handler.Callback() {@Overridepublic boolean handleMessage(Message msg) {if(SystemUtils.isAPPALive(getApplicationContext(), Contants.PACKAGE_NAME)){//APP活着的}else{Intent intent = new Intent(getApplicationContext(), SportsActivity.class);intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);startActivity(intent);//APP被杀死后重启}jobFinished( (JobParameters) msg.obj, false ); // 通知系统任务执行结束return true;}});@Overridepublic boolean onStartJob(JobParameters params) {mKeepAliveService = this;Message msg = Message.obtain(mHandler, MESSAGE_ID_TASK, params);mHandler.sendMessage(msg);// 返回false,系统假设这个方法返回时任务已经执行完毕;// 返回true,系统假定这个任务正要被执行return true;}@Overridepublic boolean onStopJob(JobParameters params) {mHandler.removeMessages(MESSAGE_ID_TASK);return false;}
}

JobScheduler管理类执行系统任务:JobSchedulerManager.java

public class JobSchedulerManager {private static final int JOB_ID = 1;private static JobSchedulerManager mJobManager;private JobScheduler mJobScheduler;private static Context mContext;private JobSchedulerManager(Context ctxt){this.mContext = ctxt;mJobScheduler = (JobScheduler)ctxt.getSystemService(Context.JOB_SCHEDULER_SERVICE);}public final static JobSchedulerManager getJobSchedulerInstance(Context ctxt){if(mJobManager == null){mJobManager = new JobSchedulerManager(ctxt);}return mJobManager;}@TargetApi(21)public void startJobScheduler(){if(AliveJobService.isJobServiceAlive() || isBelowLOLLIPOP()){return;        // 如果JobService已经启动或API<21,返回}JobInfo.Builder builder = new JobInfo.Builder(JOB_ID,new ComponentName(mContext, AliveJobService.class));builder.setPeriodic(3000); // 设置每3秒执行一下任务builder.setPersisted(true);  // 设置设备重启时,执行该任务builder.setRequiresCharging(true); // 当插入充电器,执行该任务JobInfo info = builder.build();mJobScheduler.schedule(info);  }@TargetApi(21)public void stopJobScheduler(){if(isBelowLOLLIPOP())return;mJobScheduler.cancelAll();}private boolean isBelowLOLLIPOP(){return Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP; // API< 21}
}

记得添加权限: android:permission="android.permission.BIND_JOB_SERVICE"

Doze休眠模式

谷歌在Android M(6.0)提出为了延长电池使用寿命的一种节能方式,它的核心思想是在手机处于屏幕熄灭、不插电或静止不动一段时间后,手机会自动进入Doze模式,处于Doze模式的手机将停止所有非系统应用的WalkLocks、网络访问、闹钟、GPS/WIFI扫描,包括JobSheduler活动

当进入Doze模式的手机屏幕被点亮、移动或充电时,会立即从Doze模式恢复到正常,系统继续执行被Doze模式"冷冻"的各项活着。换而言之,Doze模式不会杀死进程,只是停止了进程相关的耗电活动,使其进入"休眠"状态。至Android N(7.0)后,谷歌进一步对Doze休眠机制进行了优化,休眠机制的应用场景和使用规则进行了加强。Doze在Android 6.0中需要将手机平行放置一段时间才能开启,在7.0中则可随时开启。

因此,对于Android 5.0,JobSheduler的唤醒是非常有效的;对于Android 6.0,虽然谷歌引入了Doze模式,但通常很难真正进入Doze模式,所以JobSheduler的唤醒依然有效;对于Android 7.0,JobSheduler的唤醒会有一定的影响,我们可以在电池管理中给APP开绿色通道,防止手机Doze模式后阻止APP使用JobSheduler功能。

测试结果
    三星C9(6.0):一键清理和强制停止(force stop)都能够唤醒APP;
    三星Note4(5.0):一键清理和强制停止(force stop)都能够唤醒APP;
    华为荣耀4X(6.0):一键清理和强制停止(force stop)都能够唤醒APP;
    华为Mate8(7.0):失效(可能被华为屏蔽了);

四、华为推送SDK

Android市场推送,包括个推、小米、极光华为Push、360、魅族等。华为推送服务让一个后台运行的Service在一个独立进程里,主程序不需要常驻内存。当该后台Service接收到push消息后会以广播的方式通知主进程,触发相关回调接口。通常,被强制停止的APP无法接收到广播,但是华为push的后台Service,可以强行将APP拉起来,这是因为其在发广播时利用了Intent.FLAG_INCLUDE_STOPPED_PACKAGES标记实现的。

MyHwPushReceiver.java

该类继承了华为接收器(com.huawei.android.pushagent.api.PushEventReceive),用于接收服务器传递过来的token,获取服务器连接状态,接收服务器推送过来的通知、透传等消息。需要注意的是,onToken方法、onPushMsg方法必须要实现,并且尽量不要在MyHwPushReceiver类中开启线程、处理Handler等。

public class MyHwPushReceiver extends PushEventReceiver{private final static String TAG = "MyHwPushReceiver";@Overridepublic void onToken(Context context, String token, Bundle bundle) {Log.i(TAG,"连接到华为推送服务器,token="+token);}@Overridepublic boolean onPushMsg(Context context, byte[] msgBytes, Bundle bundle) {Log.i(TAG,"接收透传消息:"+new String(msgBytes,"UTF-8"));// 启动应用return false;}@Overridepublic void onPushState(Context context, boolean connectState) {Log.i(TAG,"是否连接到华为推送服务器:"+(connectState?"connected":"disconnected"));}@Overridepublic void onEvent(Context context, Event event, Bundle bundle) { //点击打开通知栏super.onEvent(context, event, bundle);}
}

HwPushManager.java

 public class HwPushManager {private static HwPushManager mPushManager;private Context mContext; private HwPushManager(Context mContext){this.mContext = mContext;}public static  HwPushManager getInstance(Context mContext){if(mPushManager == null){mPushManager = new HwPushManager(mContext);}return mPushManager;}public void startRequestToken(){//向服务器请求TokenPushManager.requestToken(mContext);}//是否接收服务器传递过来的透传消息public void isEnableReceiveNormalMsg(boolean isEnable){PushManager.enableReceiveNormalMsg(mContext,isEnable);}//是否接收自呈现消息public  void isEnableReceiverNotifyMsg(boolean isEnable){PushManager.enableReceiveNotifyMsg(mContext,isEnable);}
}

穿透消息,即对于信息传输通道来说不会去关心透传消息的消息体格式及内容,它只是负责消息的传递,不对消息做任何处理,当客户端接收到透传消息后,由客户端自己来决定如何处理消息,比如默默在后台处理消息、以通知的方式向用户展示消息等,因此它弥补了通知栏消息客户端无法捕获到相关动作的不足。

 AndroidManifest.xml

除了自定义的MyHwPushReceiver类,其他直接从华为推送官方Demo拷贝即可。通过华为开发者联盟网页中给KeepAppAlive发送透传消息的,测试华为推送保活的可行性。一般来说,我们都是在自己的服务器开一个定时器,定时推送透传消息到客户端。

注:部分华为手机可能还需要开启自启动权限;如何集成华为推送SDK,直接看官方文档即可;非华为手机需要安装"华为手机服务.apk"才能使用华为推送(有点坑)。

    <uses-permission android:name="android.permission.INTERNET" /><uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /><uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /><uses-permission android:name="android.permission.READ_PHONE_STATE" /><uses-permission android:name="android.permission.WAKE_LOCK" /><!-- 第三方相关 :接收Push消息(注册、Push消息、Push连接状态、标签,LBS上报结果)广播 --><receiver android:name=".receiver.MyHwPushReceiver" ><intent-filter><action android:name="com.huawei.android.push.intent.REGISTRATION" /><action android:name="com.huawei.android.push.intent.RECEIVE" /><action android:name="com.huawei.android.push.intent.CLICK" /><action android:name="com.huawei.intent.action.PUSH_STATE" /><action android:name="com.huawei.android.push.plugin.RESPONSE" /></intent-filter><meta-data android:name="CS_cloud_ablitity" android:value="@string/hwpush_ability_value"/></receiver><!-- PushSDK:PushSDK接收外部请求事件入口 --><receiverandroid:name="com.huawei.android.pushagent.PushEventReceiver"android:process=":pushservice" ><intent-filter><action android:name="com.huawei.android.push.intent.REFRESH_PUSH_CHANNEL" /><action android:name="com.huawei.intent.action.PUSH" /><action android:name="com.huawei.intent.action.PUSH_ON" /><action android:name="com.huawei.android.push.PLUGIN" /></intent-filter><intent-filter><action android:name="android.intent.action.PACKAGE_ADDED" /><action android:name="android.intent.action.PACKAGE_REMOVED" /><data android:scheme="package" /></intent-filter></receiver><receiverandroid:name="com.huawei.android.pushagent.PushBootReceiver"android:process=":pushservice" ><intent-filter><action android:name="com.huawei.android.push.intent.REGISTER" /><action android:name="android.net.conn.CONNECTIVITY_CHANGE" /></intent-filter><meta-dataandroid:name="CS_cloud_version"android:value="\u0032\u0037\u0030\u0035" /></receiver><!-- PushSDK:Push服务 --><serviceandroid:name="com.huawei.android.pushagent.PushService"android:process=":pushservice" ></service><!-- locale|layoutDirection 切换语言后不重新创建activity --><activityandroid:name="com.huawei.android.pushselfshow.richpush.RichPushActivity"android:process=":pushservice"android:theme="@style/hwpush_NoActionBar"android:configChanges="orientation|screenSize|locale|layoutDirection"android:screenOrientation="portrait"><meta-data android:name="hwc-theme"android:value="androidhwext:style/Theme.Emui"/><intent-filter><action android:name="com.huawei.android.push.intent.RICHPUSH" /><category android:name="android.intent.category.DEFAULT" /></intent-filter></activity><activityandroid:name="com.huawei.android.pushselfshow.permission.RequestPermissionsActivity"android:theme="@android:style/Theme.DeviceDefault.Light.Dialog.NoActionBar"android:launchMode="singleTop"android:screenOrientation="portrait"android:configChanges="orientation|screenSize|locale|layoutDirection"android:exported="false"></activity>

测试结果


参考链接:

https://blog.csdn.net/andrexpert/article/details/75174586

https://blog.csdn.net/andrexpert/article/details/75045678


推荐阅读:

原创 Android性能优化(一)闪退治理、卡顿优化、耗电优化、APK瘦身

Android 应用进程保活APP常驻内存研究方案相关推荐

  1. 探讨Android6.0及以上系统APP常驻内存(保活)实现-争宠篇

    探讨Android6.0及以上系统APP常驻内存(保活)实现-争宠篇 (转载请声明出处:http://blog.csdn.net/andrexpert/article/details/75045678 ...

  2. Android 禁止程序常驻内存,【教程】教你如何让指定APP常驻内存

    该楼层疑似违规已被系统折叠 隐藏此楼查看此楼 抱歉啊,说好的这篇教程来的太迟了,我们昨天(15号)有学考,所以今天才得空来写这篇简单的小教程 首先你需要符合下面几个条件 1.有一台可以正常连接手机的电 ...

  3. 解密Android7.0 8.0进程保活与拉活的实现方式 如何才能让APP常驻内存 躲避系统的追杀

    进程保活 前言 APP进程被系统杀死 Low Memory Killer 进程优先级 进程保活 1px Activity 前台Service 进程拉活 粘性Service JobScheduler 双 ...

  4. android app数据存储,基于Android开发的APP数据存储研究

    谢原武+龙文 摘要: 作为一个完整的应用程序,数据存储操作是必不可少的.Android系统一共提供了四种数据存储方式分别为File文件存储.Shared Preferences存储.ContentPr ...

  5. Android中对app应用内存的分配

    <span style="font-family: Arial; background-color: rgb(255, 255, 255);">在Android运行机制 ...

  6. Android进程保活(常驻内存)

    Android将进程分为6个等级,它们按优先级顺序由高到低依次是:  1.前台进程( FOREGROUND_APP):  2.可视进程(VISIBLE_APP ):  3. 次要服务进程(SECOND ...

  7. 百度APP iOS端内存优化实践-大块内存监控方案

    ‍ 01 背景 ‍内存不足引发的APP崩溃通常称为OOM(Out Of Memory),iOS端无法捕获OOM异常,也得不到任何堆栈信息,给我们排查和解决问题带来很多困扰.引起OOM的原因归根结底就是 ...

  8. Android进程保活--我也想乖,傻C产品就要这样

    方案 推送,保活. Netty长链接很成熟. 双service保活.(7.0已失效,阿里大神) 标题 重点内容 探讨Android6.0及以上系统APP常驻内存(保活)实现-复活篇 探讨Android ...

  9. Android进程保活拉活

    参考:腾讯视频相关视频公开课 学习资料: 探讨Android6.0及以上系统APP常驻内存(保活)实现-争宠篇 目录 一.进程的一些基本常识 二.如何保活 三.如何拉活 四.总结 一.进程的一些基本常 ...

最新文章

  1. 编程python怎么读-python怎么读sql数据?
  2. 数据库开发——MySQL——慢查询优化
  3. 【高并发】java JUC中的Semaphore(信号量)
  4. gfirefly 框架分析
  5. 论文阅读:Spatial context-aware network for salient object detection
  6. elementui table某一列是否显示_汇编语言--键盘扫描及显示实验(含代码解释)
  7. MacOS使用top命令查看进程使用内存
  8. 中科院Kaggle全球文本匹配竞赛华人第1名团队-深度学习与特征工程
  9. 地统计学之变异函数深入理解与分析
  10. java实现文本编辑器
  11. 关于-宏碁4741G换固态硬盘SSD的一些注意事项
  12. 【美赛】全面助力2023年美国大学生数学建模竞赛,祝大家取得好成绩
  13. iPhone 12手势使用技巧
  14. 高德地图发布Q2交通报告
  15. 小程序即时配送配置指南
  16. 网卡驱动修改服务器,网卡驱动配置
  17. 计算机编程ebcdic码,EBCDIC和BCD码
  18. kafka指定偏移量拉取与偏移量半自动提交
  19. vue刷新当前页面--provide / inject 用法
  20. UltraISO制作U盘启动盘安装Windows系统攻略

热门文章

  1. Android 自定义view完全解析--带你通透了解自定义view
  2. 无法定位程序输入点(cmake opencv_contrib,并配置后)
  3. java 倍数_Java硬币翻转倍数递增试算实例
  4. 概率图模型(1)--隐马尔科夫模型(1)
  5. linux的pv原语
  6. 0x00007FFEB5D49149 处(位于 Project1.exe 中)有未经处理的异常: Microsoft C++ 异常: cv::Exception,位于内存位置 0x000
  7. 三三速记英语 需要者看
  8. 永恩上线服务器维护,LOL10.16永恩BUG商城问题介绍-LOL10.16永恩BUG商城问题有哪些_牛游戏网...
  9. java获取当天开始,结束时间
  10. 教授专栏33 | 黄阳光: 投资初创企业,应如何配置资源?