Android进程保活:如何让app一直运行

目录

1)为什么需要进行进程保活呢?需求是什么?
2)进程分类
3)进程的优先级
4)如何提高进程优先级
5)如何进行进程保活

一、为什么需要进行进程保活呢?需求是什么?

比如:

  1. app在运行过程中,可能会因为各种原因导致闪退,报错或者被杀死等,尤其是一些自动售卖机,安装了android系统,如果这个时候app闪退了,那么就无法售卖了,我们需要能让程序运行起来。
  2. 如果用中有后台服务需要一直运行,例如音乐播放器、即时通讯等。
  3. 应用可能需要接收推送消息并及时展示给用户。为了实这个功能,需要保证应用进程直处于活跃状态,以便能够及时处理和显示推送消息。
  4. 有些应用需要执行定时任务,例如定时更新数据、定时发送统计信息等。通过保持进程活跃,可以确保这些任务按时执行。
  5. 某些应用需要在屏幕上显示悬浮窗口,例如悬浮球、悬浮菜单等

就需要通过进程保活来防止系统将其杀死,今天我们就来讲讲,进程保活。

二、进程分类

进程会被杀死,那么什么进程会被杀死呢?

1)前台进程(Foreground Process):前台进程是指当前正在与用户进行交互的app进程。例如,用户正在使用某个app或者app正在展示一个前台界面时;在前台运行的 Service 服务 , Service 调用了 startForeground,该app所在的进程就被认为是前台进程。前台进程拥有最高的优先级,不容易被系统杀死。

2)可见进程(Visible Process)可见进程是指虽然没有处于前台,但是对用户可见的app进程。例如,当一个Activity被另一个Activity或Dialog部分遮挡时,被遮挡的Activity所在的进程就被认为是可见进程。可见进程的优先级较高,相比后台进程更不容易被系统杀死。Activity 组件调用 onPause 生命周期函数。

3)服务进程(Service Process)调用 startService 方法启动的 Service 进程组件 , 就是服务进程 , 其没有与 Activity 组件绑定 , 因此该 Service 组件的优先级要降低一个等级 , 称为服务进程 ;

4)后台进程(Background Process):后台进程是指已经失去用户焦点且不可见的app进程。例如,当用户按Home键回到桌面时,app进入后台状态。后台进程的优先级较低,当系统内存不足时可能会被系统杀死以释放资源。

5)空进程(Empty Process):空进程是指没有任何活动组件(如Activity、Service等)的应用进程。这进程通常只是为了缓存应用的数据而保留,当需要重新启动应用时可以快速恢复。空进程的优先级最低,是系统内存不足时首先被杀死的对象。

三、那么,如何才能清楚的确认,究竟是那种进程呢?

通过oom_adj值.

oom_adj值是Linux内核为每个进程分配的,用于反映进程的优先级。在Android系统中,当内存不足需要杀死进程以回收内存时,系统会根据oom_adj值来决定是否回收该进程。oom_adj值越大,对应的进程优先级越低,越有可能被系统回收。

以下是一些oom_adj值对应的进程优先级(注意:这些值可能会因Android版本的不同而有所变化,以下信息基于参考文章提供的信息):

oom_adj值进程优先级描述
-16SYSTEM_ADJ:系统进程,具有最高优先级
0FOREGROUND_APP_ADJ:前台进程,用户当前正在交互的进程
1VISIBLE_APP_ADJ:可见进程,虽然不在前台但用户仍然可以看到(如锁屏界面上的应用)
2PERCEPTIBLE_APP_ADJ:可感知进程,如后台播放音乐、铃声、震动等
3BACKUP_APP_ADJ:进入后台的进程,按下Menu键可查看
5SERVICE_ADJ:服务进程,持有应用服务的进程

如何查看oom_adj值

在 Android Studio 中 , 可以看到该运行的程序的进程号 PID 为 30575
进入 adb shell 命令行 , su 获取 root 权限 , 使用如下命令cat /proc/30575/oom_adj
, 查询指定 PID 的 oom_adj 值就可以看到,为0就是前台进程。

那么,内存不足,多少才算不足呀?

在这里插入图片描述
这些数字,其单位是 4 K B , 80640 , 乘以 4 K B \rm 4KB 4KB , 除以1024 , 最后得到 315MB
内存不足时杀进程的优先顺序 :

18432 : 内存小于 18432 × 4 K B \rm 18432 \times 4KB 18432×4KB 时 , 杀 " 前台进程 " ;
23040 : 内存小于 23040 × 4 K B \rm 23040 \times 4KB 23040×4KB 时 , 杀 " 可见进程 " ;
27648 : 内存小于 27648 × 4 K B \rm 27648 \times 4KB 27648×4KB 时 , 杀 " 服务进程进程 " ;
32256 : 内存小于 32256 × 4 K B \rm 32256 \times 4KB 32256×4KB 时 , 杀 " 后台进程 " ;
55296 : 内存小于 55296 × 4 K B \rm 55296 \times 4KB 55296×4KB 时 , 杀 " ContentProvider 进程 " ;
80640 : 内存小于 80640 × 4 K B \rm 80640 \times 4KB 80640×4KB 时 , 杀 " 空进程 " ;

四、如何提高进程优先级

了解了这么多,我们知道前台进程不容易被杀死,假如我们变成了其他进程,那么如何才能提高他的优先级呢?

4.1 前台 Service

(1)service

import android.app.Notification  
import android.app.NotificationChannel  
import android.app.NotificationManager  
import android.app.Service  
import android.content.Context  
import android.content.Intent  
import android.os.Build  
import android.os.IBinder  class MyForegroundService : Service() {  private val NOTIFICATION_ID = 1  private val CHANNEL_ID = "ForegroundServiceChannel"  override fun onCreate() {  super.onCreate()  val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager  // 创建通知渠道(Android 8.0+)  if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {  val channel = NotificationChannel(  CHANNEL_ID,  "Foreground Service Channel",  NotificationManager.IMPORTANCE_LOW  )  notificationManager.createNotificationChannel(channel)  }  // 启动前台服务  startForeground(NOTIFICATION_ID, getNotification("服务正在运行..."))  }  override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {  // 处理从Activity传递过来的数据(如果有的话)  return START_STICKY  }  override fun onBind(intent: Intent?): IBinder? {  return null  }  private fun getNotification(contentText: String): Notification {  val builder = Notification.Builder(this, CHANNEL_ID)  .setSmallIcon(R.drawable.ic_notification) // 设置图标,确保你有这个资源  .setContentTitle("前台服务示例")  .setContentText(contentText)  .setPriority(Notification.PRIORITY_LOW)  // 可以在这里添加其他通知设置,如声音、振动等  return builder.build()  }  
}

(2)注册服务

<application  ...  >  ...  <service  android:name=".MyForegroundService"  android:enabled="true"  android:exported="false" />  ...  
</application>

(3)activity

import android.content.Intent  
import android.os.Bundle  
import androidx.appcompat.app.AppCompatActivity  class MainActivity : AppCompatActivity() {  override fun onCreate(savedInstanceState: Bundle?) {  super.onCreate(savedInstanceState)  setContentView(R.layout.activity_main)  // 启动前台服务  val serviceIntent = Intent(this, MyForegroundService::class.java)  startService(serviceIntent)  }  // 其他方法...  
}

好了,我们可以运行程序看看,比如按home键,然后再读取oom_adj值,看看有没有生效。

五、如何进行进程保活

通过上述信息,那么我们就可以知道,我们现在的进程究竟是什么?为我们接下来要进行进程保活做铺垫。进程保活是指在Android系统,通过一些手段和技术手段来确保应用进程持续运行的一种机制。

5.1 双进程保活

进程之间相互监听销毁的状态,从而重新启动对方。通过ServiceConnection 来进行监听。

(1)activity

startService(Intent(this, AService.java))
startService(Intent(this, BService.java))

(2)service


public class AService extends Service {private Connection connection;@Overridepublic IBinder onBind(Intent intent) {return null;}@Overridepublic void onCreate() {super.onCreate();// 启动前台进程startService();}private void startService() {// 创建通知通道NotificationChannel channel = new NotificationChannel("service","service", NotificationManager.IMPORTANCE_NONE);channel.setLightColor(Color.BLUE);channel.setLockscreenVisibility(Notification.VISIBILITY_PRIVATE);NotificationManager service = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);// 正式创建service.createNotificationChannel(channel);NotificationCompat.Builder builder = new NotificationCompat.Builder(this, "service");Notification notification = builder.setOngoing(true).setSmallIcon(R.mipmap.ic_launcher).setPriority(PRIORITY_MIN).setCategory(Notification.CATEGORY_SERVICE).build();startForeground(10, notification);}/*** 绑定 另外一个 服务*/private void bindService() {// 创建连接对象connection = new Connection();// 创建本地前台进程组件意图Intent bindIntent = new Intent(this, BService.class);// 绑定进程操作bindService(bindIntent, connection, BIND_AUTO_CREATE);}@Overridepublic int onStartCommand(Intent intent, int flags, int startId) {// 绑定另外一个服务bindService();return START_STICKY; // 尝试在系统杀死服务后重新创建它}class Connection implements ServiceConnection {@Overridepublic void onServiceConnected(ComponentName name, IBinder service) {// 服务绑定成功时回调}@Overridepublic void onServiceDisconnected(ComponentName name) {// 再次启动前台进程startService();// 绑定另外一个远程进程bindService();}}}

(3)service


public class BService extends Service {private Connection connection;@Overridepublic IBinder onBind(Intent intent) {return null;}@Overridepublic void onCreate() {super.onCreate();// 启动前台进程startService();}private void startService(){// 创建通知通道NotificationChannel channel = new NotificationChannel("service","service", NotificationManager.IMPORTANCE_NONE);channel.setLightColor(Color.BLUE);channel.setLockscreenVisibility(Notification.VISIBILITY_PRIVATE);NotificationManager service = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);// 正式创建service.createNotificationChannel(channel);NotificationCompat.Builder builder = new NotificationCompat.Builder(this, "service");Notification notification = builder.setOngoing(true).setSmallIcon(R.mipmap.ic_launcher).setPriority(PRIORITY_MIN).setCategory(Notification.CATEGORY_SERVICE).build();startForeground(10, notification);}/*** 绑定 另外一个 服务*/private void bindService(){// 创建连接对象connection = new Connection();// 创建本地前台进程组件意图Intent bindIntent = new Intent(this, AService.class);// 绑定进程操作bindService(bindIntent, connection, BIND_AUTO_CREATE);}@Overridepublic int onStartCommand(Intent intent, int flags, int startId) {// 绑定另外一个服务bindService();return START_STICKY; // 尝试在系统杀死服务后重新创建它}class Connection implements ServiceConnection {@Overridepublic void onServiceConnected(ComponentName name, IBinder service) {// 服务绑定成功时回调}@Overridepublic void onServiceDisconnected(ComponentName name) {// 再次启动前台进程startService();// 绑定另外一个远程进程bindService();}}}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/389486.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

mysql高级语句的查询语句

一、排序语法&#xff0c;关键字排序 升序和降序 默认的排序方式就是升序 升序&#xff1a;ASC 降序&#xff1a;DESC 配合语法&#xff1a;order by 语法 1、升序 select * from info order by name; 根据名字升序排序&#xff0c;不需要加ASC select * from info order…

ChinaJoy 2024,VERYCLOUD睿鸿股份与你相聚

&#x1f3ae;2024 ChinaJoy于26日正式开幕 &#x1f557;7月26-28日 &#x1f310;VERYCLOUD睿鸿股份在BTOB商务洽谈馆 &#x1f31f;W4-B785展位 &#x1f387;展台交流好礼相送 与多行业好友现场相聚、畅谈&#x1f9d0; 现场游戏企业云集 专业观众、玩家纷至沓来 与游戏/短…

配置frp实现内网穿透(.toml配置文件)

简介 frp 是一款高性能的反向代理应用&#xff0c;专注于内网穿透。它支持多种协议&#xff0c;包括 TCP、UDP、HTTP、HTTPS 等&#xff0c;并且具备 P2P 通信功能。使用 frp&#xff0c;您可以安全、便捷地将内网服务暴露到公网&#xff0c;通过拥有公网 IP 的节点进行中转。…

APACHE安装与应用

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:Linux运维老纪的首页…

乱弹篇(40)人类追求长寿

不要认为只有中国的老龄化才严重&#xff0c;实际上全球都面临老龄化&#xff0c;其中日本最为严重。 这是随着人类生活和医学水平的不断提高&#xff0c;寿命才会比过去数十年有了大幅度的提升。据资料显示&#xff0c;目前全球平均预期寿命估计为73岁。与百年之前相比&#…

上半年手游出海吸金超624亿,混合变现帮助游戏提升收益

2024年上半年&#xff0c;海外游戏市场总收入达到惊人的325亿美元&#xff0c;App Store平台收入同比增长11%。这一数据反映了手游市场的巨大潜力和活力&#xff0c;不论是在App Store还是Google Play&#xff0c;玩家们对手游的热情有增无减&#xff0c;支撑了开发者们收益的不…

5行代码快速Git配置ssh

0 流程步骤 检查本地主机是否已经存在ssh key生成ssh key获取ssh key公钥内容&#xff08;id_rsa.pub&#xff09;复制该内容&#xff0c;到Github账号上添加公钥&#xff0c;进入Settings设置验证是否设置成功 1 代码 # 1.检查本地主机是否已经存在ssh key cd ~/.ssh ls # …

WEB前端15-Router路由

Vue2-router路由 在使用Vue.js构建现代单页面应用程序&#xff08;SPA&#xff09;时&#xff0c;路由管理是至关重要的一部分。Vue Router 是 Vue.js 官方的路由管理器&#xff0c;它允许你在应用程序中实现基于组件的页面导航。本文将介绍Vue Router的基本概念和用法&#x…

LSTM与GNN强强结合!全新架构带来10倍推理速度提升

今天来推荐一个深度学习领域很有创新性的研究方向&#xff1a;LSTM结合GNN。 GNN擅长处理图数据关系和特征&#xff0c;而LSTM擅长处理时间序列数据及长期依赖关系。通过将两者结合&#xff0c;我们可以有效提升时间序列预测的准确性和效率&#xff0c;尤其是在处理空间和时间…

vue配置多个环境变量ENV【收藏版】

vue配置多个环境变量 1. 创建环境变量文件 在你的Vue项目根目录下&#xff0c;你可以创建以下环境变量文件&#xff1a; .env&#xff1a;所有环境都会加载的通用变量。 .env.local&#xff1a;本地覆盖&#xff0c;不会被git跟踪。 .env.[mode]&#xff1a;只有指定模式才会…

光伏气象仿真系统有什么优势?

光伏气象仿真系统作为这一领域的核心工具&#xff0c;凭借其独特的优势&#xff0c;正逐步成为行业标配。本文将围绕数据可靠性、功能齐全性、海外布局支持、系统开放性以及合作方式灵活性五个方面&#xff0c;深入探讨光伏气象仿真系统的显著优势。 1.数据可靠&#xff1a;权威…

Java中的Heap(堆)(如果想知道Java中有关堆的知识点,那么只看这一篇就足够了!)

前言&#xff1a;&#xff08;Heap&#xff09;是一种特殊的完全二叉树&#xff0c;它在诸多算法中有着广泛的应用&#xff0c;本文将详细介绍Java中的堆。 ✨✨✨这里是秋刀鱼不做梦的BLOG ✨✨✨想要了解更多内容可以访问我的主页秋刀鱼不做梦-CSDN博客 先让我们看一下本文大…

微信小程序-获取手机号:HttpClientErrorException: 412 Precondition Failed: [no body]

问题&#xff1a; 412 异常就是你的请求参数获取请求头与服务器的不符&#xff0c;缺少请求体&#xff01; 我的问题&#xff1a; 我这里获取微信手机号的时候突然给我报错142&#xff0c;但是代码用的是原来的代码&#xff0c;换了一个框架就噶了&#xff01; 排查问题&am…

Springboot手工艺品交易平台—计算机毕业设计源码11541

摘 要 信息化社会内需要与之针对性的信息获取途径&#xff0c;但是途径的扩展基本上为人们所努力的方向&#xff0c;由于站在的角度存在偏差&#xff0c;人们经常能够获得不同类型信息&#xff0c;这也是技术最为难以攻克的课题。针对手工艺品交易平台等问题&#xff0c;对手工…

【MySQL进阶】事务隔离级别 MVCC

目录 MySQL事务隔离级别 1. 读未提交&#xff08;Read Uncommitted&#xff09; 2. 读已提交&#xff08;Read Committed&#xff09; 3. 可重复读&#xff08;Repeatable Read&#xff09;(默认隔离级别) 4. 串行化&#xff08;Serializable&#xff09; 表格总结 MVCC …

抖音爬虫-批量下载主页作品

使用说明 config.ini是配置文件&#xff0c;可配置文件名规则、下载视频图文音乐等。 DownloadList.txt是批量下载清单&#xff0c;可配置批量下载类型和地址。 打开软件&#xff0c;选择对应的功能&#xff0c;第一次扫码登录&#xff08;后续可自动加载cookie登录&#xff…

揭秘循环购模式:消费即收益

大家好&#xff0c;我是你们的电商策略顾问吴军。今天&#xff0c;我将带大家深入探索一种别开生面的商业模式——循环购模式。这种模式究竟有何魅力&#xff0c;能让消费者在享受购物乐趣的同时&#xff0c;还能获得额外的收益&#xff1f;更有趣的是&#xff0c;一些商家通过…

区块链软硬件协同,做产业数字化转型的“安全官” |《超话区块链》直播预告

今年的两会政府工作报告提出&#xff1a;“产业的数字化&#xff08;行业数字化转型&#xff09;是发展新质生产力的核心&#xff0c;是推动产业升级实现高质量发展的关键。”全面推进产业数字化&#xff0c;需要技术创新与产业应用深入协同&#xff1b;立足可持续发展的长远目…

Java面试八股之简述spring boot的目录结构

简述spring boot的目录结构 Spring Boot 项目遵循标准的 Maven 或 Gradle 项目布局&#xff0c;并且有一些约定的目录用于组织不同的项目组件。下面是一个典型的 Spring Boot 项目目录结构&#xff1a; src/main/java&#xff1a;包含所有的 Java 源代码&#xff0c;通常按包组…

OpenCV仿射变换实现图像扭曲与旋转

目录 1. 仿射变换 2. 仿射变换的求解 3. 代码实现 3.1 图像扭曲 3.2 图像旋转 参考内容 1. 仿射变换 仿射变换是一种可以表达为乘以一个矩阵&#xff08;线性变换&#xff09;再加上一个向量&#xff08;平移&#xff09;的变换。在几何中&#xff0c;就是将一个向量空间…