Android 2020年最新保活方案 保活90% 已适配8.0 ,9.0, 10.0(酷狗音乐)
- 红色部分是容易被回收的进程,属于android进程
- 绿色部分是较难被回收的进程,属于android进程
- 其他部分则不是android进程,也不会被系统回收,一般是ROM自带的app和服务才能拥有
如何查看某个进程的oom_adj数值呢?
oom_adj 存储在proc/PID/oom_adj文件中,其中PID是进程的id,直接 adb shell进入手机根目录查看这个文件即可。
演示一下:以我自己的项目为例,app中有两个进程,一个是主进程,另一个是运行service的进程取名为:remote。首先用android studio查看每个进程的PID:
查看命令
【1】adb shell
【2】ps
【3】cat /proc/进程id/oom_adj
举例:cat /proc/20084/oom_adj
1.在前台是0,后台是3
===================================================
优化思路:
- 提高进程的优先级,降低自己应用在退回后台时候的oom_adj值
- 在进程被kill之后能够唤醒
- 优化应用内存,正在进行中...
1.像素Activity
该方案适用场景: 本方案主要解决第三方应用及系统管理工具在检测到锁屏事件后一段时间内会杀死后台进程.适用于android所有版本。1像素Activity的特点: 需要设置该activity的style设置透明,在手机锁屏时start;在屏幕解锁时finish,主要作用就是在App退到后台之后且锁屏的时候启动一个看不见的Activity,造成一个该App没有回退到后台的假象,降低被杀的几率,伪代码如下:
protected void onCreate(Bundle savedInstanceState) {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
super.onCreate(savedInstanceState);
//设定一像素的activity
//设定一像素的activity
Window window = getWindow();
Window window = getWindow();
window.setGravity(Gravity.START | Gravity.TOP);
window.setGravity(Gravity.START | Gravity.TOP);
WindowManager.LayoutParams params = window.getAttributes();
WindowManager.LayoutParams params = window.getAttributes();
params.x = 0;
params.x = 0;
params.y = 0;
params.y = 0;
params.height = 1;
params.height = 1;
params.width = 1;
params.width = 1;
window.setAttributes(params);
window.setAttributes(params);
}
public void onReceive(final Context context, Intent intent) {
public void onReceive(final Context context, Intent intent) {
Log.i("ScreenStateReceiver", "---屏幕锁屏监听---");
Log.i("ScreenStateReceiver", "---屏幕锁屏监听---");
if (action.equals(Intent.ACTION_SCREEN_OFF)) {
if (action.equals(Intent.ACTION_SCREEN_OFF)) {
//屏幕锁定,开启OnePixelActivity
//屏幕锁定,开启OnePixelActivity
} else if (action.equals(Intent.ACTION_SCREEN_ON)) {
else if (action.equals(Intent.ACTION_SCREEN_ON)) {
//屏幕解锁,finish OnePixelActivity
//屏幕解锁,finish OnePixelActivity
}
}
说起来很简单,但是还是有几个知识点需要注意下。
关于这一点有一个细节需要处理,为了放置用户快速 进行锁屏和截屏的切换操作,而导致OnePixelActivity频繁开关。需要用一个Handler发送一个延迟消息处理最佳:
private Handler mHandler;
private Handler mHandler;
private boolean isScreenOn = true;
private boolean isScreenOn = true;
private PendingIntent pendingIntent;
private PendingIntent pendingIntent;
private List<ScreenStateListener> screenStateListeners = null;
private List<ScreenStateListener> screenStateListeners = null;
@Override
@Override
public void onReceive(final Context context, Intent intent) {
public void onReceive(final Context context, Intent intent) {
String action = intent.getAction();
String action = intent.getAction();
if (action.equals(Intent.ACTION_SCREEN_OFF)) {
if (action.equals(Intent.ACTION_SCREEN_OFF)) {
//标记屏幕为锁屏状态
//标记屏幕为锁屏状态
isScreenOn = false;
isScreenOn = false;
//开启一像素的Activity
//开启一像素的Activity
startOnePixelActivity(context);
startOnePixelActivity(context);
} else if (action.equals(Intent.ACTION_SCREEN_ON)) {
else if (action.equals(Intent.ACTION_SCREEN_ON)) {
//标记屏幕为解屏状态
//标记屏幕为解屏状态
isScreenOn = true;
isScreenOn = true;
if(pendingIntent!=null){
if(pendingIntent!=null){
pendingIntent.cancel();
pendingIntent.cancel();
}
}
}
//开启一像素的Activity
//开启一像素的Activity
private void startOnePixelActivity(final Context context){
private void startOnePixelActivity(final Context context){
if(mHandler==null){
if(mHandler==null){
mHandler = new Handler(Looper.myLooper());
mHandler = new Handler(Looper.myLooper());
}
mHandler.postDelayed(new Runnable() {
mHandler.postDelayed(new Runnable() {
@Override
@Override
public void run() {
public void run() {
//如果屏幕此时已经打开,则不执行
//如果屏幕此时已经打开,则不执行
if(isScreenOn){
if(isScreenOn){
return;
return;
}
if(pendingIntent!=null){
if(pendingIntent!=null){
pendingIntent.cancel();
pendingIntent.cancel();
}
Intent startOnePixelActivity = new Intent(context, OnePixelActivity.class);
Intent startOnePixelActivity = new Intent(context, OnePixelActivity.class);
startOnePixelActivity.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
startOnePixelActivity.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
//启动一像素包活activity
//启动一像素包活activity
pendingIntent = PendingIntent.getActivity(context, 0, startOnePixelActivity, 0);
pendingIntent = PendingIntent.getActivity(context, 0, startOnePixelActivity, 0);
try {
try {
pendingIntent.send();
pendingIntent.send();
} catch (Exception e) {
catch (Exception e) {
e.printStackTrace();
e.printStackTrace();
}
notifyScreenOff();
notifyScreenOff();
}
},1000);
1000);
}
<activity android:name=".OnePixelActivity"
<activity android:name=".OnePixelActivity"
android:theme="@style/onePixelActivity"
android:theme="@style/onePixelActivity"
android:launchMode="singleInstance"
android:launchMode="singleInstance"
android:excludeFromRecents="true"/>
android:excludeFromRecents="true"/>
为什么需要将此Activity的启动模式设置为singleInstance呢?原因是因为如果设置成其他模式,如果按照如下步骤操作的话会出现不友好的状况:
1、启动App(比如进入MainActivity),按home键让app返回后台
2、锁定屏幕,此时注册好的监听广播会启动OnePixelActivity
3、解锁屏幕,此时广播接受到此广播后会finish 掉OnePixelActivity.
因为OnePixelActivity是非singleInstance,所以此时本来已经进入后台的MainActivity的页面会自动打开。给用户造成干扰:我明明已经按下home键了,怎么此页面又自动打开了?而换成OnePixelActivity的启动模式改成singleInstance的话就可以很好的避免此问题。
另外需要注意的是,当屏幕解锁的时候,OnePixelActivity的onResume得到执行,所以在该Activity的onResume方法执行finish效果最好:
//OnePixelActivity的onResume
protected void onResume() {
protected void onResume() {
super.onResume();
super.onResume();
if (DeviceUtils.isScreenOn(this)) {//如果屏幕已经打开
if (DeviceUtils.isScreenOn(this)) {//如果屏幕已经打开
finish();
finish();
}
}
2.播放无声音乐
播放无声音乐:原理:
处理逻辑跟OneActivity一样,在App回到后台且锁屏的时候在Service里播放一个无声的mp3文件,当解锁的时候暂停改mp3的播放。
if(screenOn){//屏幕解锁
(screenOn){//屏幕解锁
puseMp3();
puseMp3();
}else{//锁屏
else{//锁屏
playMp3();
playMp3();
所以此是可以在程序启动的时候启用这个service,在在service里面注册锁屏广播,需要注意的一些地方(此Service姑且称之为KeepAliveService):
//播放无声音乐的Service
public class KeepAliveService extends Service {
class KeepAliveService extends Service {
private boolean isScreenON = true;//控制暂停
private boolean isScreenON = true;//控制暂停
private MediaPlayer mediaPlayer;
private MediaPlayer mediaPlayer;
//锁屏广播监听
//锁屏广播监听
private ScreenStateReceiver screenStateReceiver;
private ScreenStateReceiver screenStateReceiver;
@Override
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
public int onStartCommand(Intent intent, int flags, int startId) {
//注册锁屏广播
//注册锁屏广播
registerScreenStateReceiver();
registerScreenStateReceiver();
//初始化播放器
//初始化播放器
initMediaPlayer();
initMediaPlayer();
return START_STICKY;
return START_STICKY;
}
}
需要注意的是在播放器播放的时候,需要判断当前情况是否是解屏状态,而且在播放完成监听里面,继续调用start方法循环播放mp3,部分代码如下(本篇博文只贴部分关键代码,全部代码点此查看):
2、将HideNotifactionService调用startForeground将其设置为前台Service!
3、但是该Service调用startForeground方法的时候,第一个参数传的ID跟KeepAliveService调用时传同样的ID。
这样的话就确保有HideNotifactionService和KeepAliveService两个发送具有同样ID的Notification!
4、调用HideNotifactionService的stopSelf方法关闭自己,随着这个Service的关闭,通知栏的那条相同id的通知也就没了;但是同样确保了KeepAliveService的进程优先级得到了提高!
HideNotifactionService代码如下:
可以创建另一个Service,名为HideNotifactionService,该Service在KeepAliveService里面启动之
//KeepAliveService的onStartCommand方法
public int onStartCommand(Intent intent, int flags, int startId) {
public int onStartCommand(Intent intent, int flags, int startId) {
//省略注册锁屏广播以及初始化播放器的代码
//省略注册锁屏广播以及初始化播放器的代码
//将自己设置为前台Service
//将自己设置为前台Service
startForeground(this);
startForeground(this);
//启动HideNotificationService
//启动HideNotificationService
startService(new Intent(this, HideNotificationService.class));
startService(new Intent(this, HideNotificationService.class));
return START_STICKY;
return START_STICKY;
}
前面3种是保活方案
一。JobServcie 拉活
android9.0系统下,讨论如何延长APP退到后台的保活/复活时间
一、7.0及以上不存在真正意义的保活。
二、盘点目前在9.0上,可能有效的“白色手段”保活手段(这里不讨论黑色和灰色手段)。
1.仿TIM引导用户打开“后台自启动”和加入“手机白名单”。
测试开始后台自启动,测试通知栏多久还能收到通知
华为M10 9.0
时长3到5小时没被杀死
VIVO x23 9.0(数字以分钟计算)
1 Y收到
2 Y
3 Y
6 Y
8 通知栏已无通知(app被系统杀死)
10 N收不到
抛出问题:使用H5界面引导用户打开后台自启动,用户如果会同意吗?
2.开启前台服务,会生成多余的通知,被产品否定
3.优化应用内存,正在进行中...
4.仿网易云音乐,复写锁屏界面。
5.集成华为/小米/oppo/vivo/魅族手机系统级推送。
6.集成“信鸽/个推/极光/友盟等”第三方推送,以期达到关联启动。
三、盘点已经失效或者不适合的保活黑科技,这里的“不适合”是因为我们做政府项目,后台是布在内网上的。
1.双进程守护方案,华为6.0就失效
2.监听锁屏/亮屏/解锁广播,打开1像素Activity,华为6.0就失效,因广播被取消了
3.故意在后台播放无声的音乐,华为M10手机9.0失效
4.使用JobScheduler唤醒Service,7.0以上失效
5.集成华为/小米/oppo/vivo/魅族等push,因为项目本地化部署,不适合
6.推送互相唤醒复活:极光、友盟、以及各大厂商的推送,因为项目本地化部署,不适合
7.同派系APP广播互相唤醒:比如今日头条系、阿里系,因为项目本地化部署,不适合
8.使用自定义锁屏界面:覆盖了系统锁屏界面。网易云音乐就是如此,但是会生成一个常驻通知栏的通知
9.把APP设置为系统应用,不适合,因为需要权限等
10.native进程(已报废)
11.利用账号同步机制拉活,失效了
12. 提高Service优先级,比如onStartCommand返回START_STICKY,没什么效果
Android 2020年最新保活方案 保活90% 已适配8.0 ,9.0, 10.0(酷狗音乐)相关推荐
- Android获取酷狗音乐歌曲详情
Android获取酷狗音乐歌曲详情 一.目标 二.失效的实现方式 三.可用的实现方式 四.参考资料 五.写在最后 一.目标 酷狗音乐歌曲详情包括以下信息. 字段 描述 title 标题,即歌曲名称 a ...
- Android获取酷狗音乐歌曲详细信息
Android获取酷狗音乐歌曲详细信息 一.目标 二.实现方案 三.最终方案 四.网易云音乐 五.遗留问题 六.接下来 七.Finally 在<Android获取歌曲详细信息>一文中,介绍 ...
- android 酷狗demo_酷狗音乐Android客户端详细使用评测
曾经现在酷狗音乐一直是PC机上必装的音乐播放软件,手机音乐播放器哪个好用呢,酷狗音乐Android客户端也经过几个版本更新,版酷狗音乐的功能,界面都趋于完美.下面来看看酷狗音乐Android客户端详细 ...
- 酷狗android平板,安卓平板车载共享 体验酷狗音乐HD版
安卓平板车载共享 体验酷狗音乐HD版 2013年04月24日 13:53作者:马承平编辑:马承平文章出处:泡泡网原创 分享 泡泡网影音相关频道4月24日 自苹果iPad及各品牌Android平板面世以 ...
- android酷狗界面,酷狗音乐Android 2.2版系统优化版界面曝光
酷狗音乐Android 2.2版系统优化版界面曝光 2011-03-23 13:30:13 来源:cnbeta 扫码可以: 1.在手机上浏览 2.分享给微信好友或朋友圈 摘要: 酷狗音乐也针对And ...
- android 酷狗demo_酷狗音乐(Android)v8.1.5去广告清爽版
本帖最后由 三生三世 于 2016-7-11 10:56 编辑 酷狗音乐安卓版更新至v8.1.5版.酷狗音乐(Android)是迄今为止最强大,最多人使用的音乐软件!有强大的音乐搜索,高速下载,海量曲 ...
- Android QQ音乐/酷狗音乐锁屏控制实现原理,酷狗锁屏
混乱的锁屏控制 Android自4.0版本, 也就是API level 14开始, 加入了锁屏控制的功能, 相关的类是RemoteControlClient, 这个类在API level 21中被标记 ...
- Android版酷狗音乐 v9.0.1 去广告SVIP珍藏V2版
by YYY~清羽 ◎兼容最新版MIUI系统 ◎去除启动页,首页,专辑页,听歌识曲页广告 ◎去除多余权限,服务,广播接收器,内容提供商 ◎去除安卓8以上系统的"正在运行通知" ◎去 ...
- 使用android studio时酷狗音乐,17 Android Studio开发实战:音乐播放器——浪花音乐...
手机上的多媒体内容讲究声情并茂.悦目且悦耳,这样才能让用户的感官得到最大享受.影视播放器由于存在视频自身的画面,反而限制了开发者的施展空间:而音乐播放器允许定制播放画面,开发者有足够空间施展拳脚.本节 ...
- Android插件化开发指南——实践之仿酷狗音乐首页
文章目录 1. 前言 2. 布局分析 3. 底部导航栏的实现 4. 顶部导航栏和ViewPager+Fragment的关联 1. 前言 在Android插件化开发指南--2.15 实现一个音乐播放器A ...
最新文章
- python使用matplotlib可视化函数曲线、设置y轴为对数坐标(log scale)、默认情况下坐标轴为线性坐标
- VIM编辑器(第十章)
- 汇编语言随笔(1)- 初步介绍和寄存器概览
- GitHub 实现多人协同提交代码并且权限分组管理
- Codeforces Round #FF (Div. 1) A. DZY Loves Sequences
- java 压缩 乱码_如何解决java压缩文件乱码问题
- 奖金(信息学奥赛一本通-T1352)
- python中import问题
- Cesium加载GeoServer发布的SHP和GeoTIFF文件
- 学习EXT第八天:EXT的布局(Layout)Part 1
- XeCJK 使用系统字体
- wx2540h配置教程_H3C无线AP控制器EWP-WX2540H 无线AP 无线云台控制器 无线控制器
- STM32f107 CAN滤波器设置
- PCIE--1--概念认知
- SQL 发送Email
- 二分类最优阈值确定_一文搞懂分类算法中常用的评估指标
- 计算机专业选择福大还是南邮,48所院校考研历年报录比汇总,21考研可参考!...
- UnhandledPromiseRejectionWarning: MongoError: command insert requir es authentication
- Anno六轴机械臂solidworks转urdf
- mysql8.0.19中在navicat客户端中int、bigint等类型设置长度保存后为0