App为什么会被杀死

一般情况App被杀有以下几种情况
1 手机内存不足,系统需要花费更多资源去运行优先级较高的应用
2 第三方的管理软件比如360,腾讯管家,清理进程也可能会杀死进程

Android系统会优先杀死进程优先级较低的应用,如果应用的优先级相同,那么系统会优先杀死占用内存较多的应用。
所以要使得我们的应用长时间保活,正常的做法是提高优先级以及优化内存使用,不要出现内存泄漏等现象。

Android进程优先级:
以下内容拷贝自Android 官网
https://developer.android.com/guide/components/activities/process-lifecycle

为了确定在内存不足时应该终止哪些进程,Android
会根据每个进程中运行的组件以及这些组件的状态,将它们放入“重要性层次结构”。这些进程类型包括(按重要性排序):

1.A 前台进程是用户目前执行操作所需的进程。在不同的情况下,进程可能会因为其所包含的各种应用组件而被视为前台进程。如果以下任一条件成立,则进程会被认为位于前台:
它正在用户的互动屏幕上运行一个 Activity(其 onResume() 方法已被调用)。 它有一个 BroadcastReceiver
目前正在运行(其 BroadcastReceiver.onReceive() 方法正在执行)。 它有一个 Service
目前正在执行其某个回调(Service.onCreate()、Service.onStart() 或
Service.onDestroy())中的代码。
系统中只有少数此类进程,而且除非内存过低,导致连这些进程都无法继续运行,才会在最后一步终止这些进程。通常,此时设备已达到内存分页状态,因此必须执行此操作才能使用户界面保持响应。

2.可见进程正在进行用户当前知晓的任务,因此终止该进程会对用户体验造成明显的负面影响。在以下条件下,进程将被视为可见: 它正在运行的 Activity 在屏幕上对用户可见,但不在前台(其 onPause() 方法已被调用)。举例来说,如果前台 Activity
显示为一个对话框,而这个对话框允许在其后面看到上一个 Activity,则可能会出现这种情况。 它有一个 Service 正在通过
Service.startForeground()(要求系统将该服务视为用户知晓或基本上对用户可见的服务)作为前台服务运行。
系统正在使用其托管的服务实现用户知晓的特定功能,例如动态壁纸、输入法服务等。
相比前台进程,系统中运行的这些进程数量较不受限制,但仍相对受控。这些进程被认为非常重要,除非系统为了使所有前台进程保持运行而需要终止它们,否则不会这么做。

3.服务流程包含一个已使用 startService() 方法启动的 Service。虽然用户无法直接看到这些进程,但它们通常正在执行用户关心的任务(例如后台网络数据上传或下载),因此系统会始终使此类进程保持运行,除非没有足够的内存来保留所有前台和可见进程。
已经运行了很长时间(例如 30 分钟或更长时间)的服务的重要性可能会降位,以使其进程降至下文所述的缓存 LRU
列表。这有助于避免超长时间运行的服务因内存泄露或其他问题占用大量内存,进而妨碍系统有效利用缓存进程。

4.缓存进程是目前不需要的进程,因此,如果其他地方需要内存,系统可以根据需要自由地终止该进程。在正常运行的系统中,这些是内存管理中涉及的唯一进程:运行良好的系统将始终有多个缓存进程可用(为了更高效地切换应用),并根据需要定期终止最早的进程。只有在非常危急(且具有不良影响)的情况下,系统中的所有缓存进程才会被终止,此时系统必须开始终止服务进程。
这些进程通常包含用户当前不可见的一个或多个 Activity 实例(onStop() 方法已被调用并返回)。只要它们正确实现其
Activity 生命周期(详情请见 Activity),那么当系统终止此类流程时,就不会影响用户返回该应用时的体验,因为当关联的
Activity 在新的进程中重新创建时,它可以恢复之前保存的状态。

这些进程保存在伪 LRU
列表中,列表中的最后一个进程是为了回收内存而终止的第一个进程。此列表的确切排序政策是平台的实现细节,但它通常会先尝试保留更多有用的进程(比如托管用户的主屏幕应用、用户最后看到的
Activity
的进程等),再保留其他类型的进程。还可以针对终止进程应用其他政策:比如对允许的进程数量的硬限制,对进程可持续保持缓存状态的时间长短的限制等。
在决定如何对进程进行分类时,系统会参考进程中当前活动的所有组件中最重要的级别。请参阅 Activity、Service 和 BroadcastReceiver 文档,详细了解这些组件各自对进程的整体生命周期有何影响。每个类的文档都详细介绍了它们对应用的整个生命周期有何影响。
进程的优先级也可能因从属于进程的其他依赖项而提升。例如,如果进程 A 已通过 Context.BIND_AUTO_CREATE 标记绑定到 Service,或在使用进程 B 中的 ContentProvider,则进程 B 的分类始终至少和进程 A 一样重要。
上面说了 正规的让我们应用保活的方式有
1.提高进程优先级
2.减少内存的开销
除了正规保活方式 自然也有黑科技 那就是双进程守护

2 双进程守护Demo

原理比较简单 就是利用notification将Service设置为前台服务 提高进程优先级,并相互bind,两个Service互为远程Service,进程不一样。这样当Android设备一个一个杀死进程的时候,就只能杀死一个Service的进程,另外一个Service进程会唤起被杀的进程。

2.1示例代码

因为互为远程Service 因此需要利用AIDL将两个Service都变成远程Service

// IRemoteServiceConn.aidl
package com.example.processgaurd;// Declare any non-default types here with import statementsinterface IRemoteServiceConn {}

两个Service的定义

public class MainService extends Service {private static final String TAG = "MainService";private static final int SERVICE_ID = 0x11;@Overridepublic void onCreate() {super.onCreate();Log.e(TAG, " MainService 创建 onCreate: ");new Thread(() -> {while (true) {Log.e(TAG, "MainService 等待接收消息");try {Thread.sleep(2000 * 20);} catch (InterruptedException e) {e.printStackTrace();}}}).start();}@RequiresApi(api = Build.VERSION_CODES.O)@Overridepublic int onStartCommand(Intent intent, int flags, int startId) {Log.e(TAG, " MainService启动 onStartCommand: ");// 提高进程优先级startForeground(SERVICE_ID, Util.getNotification(MainService.this, MainService.class, "111", "1111"));// 尝试bind remote GuardServiceIntent guardIntent = new Intent(MainService.this, GuardService.class);bindService(guardIntent,mServiceConnection, Context.BIND_IMPORTANT);return super.onStartCommand(intent, flags, startId);}@Nullable@Overridepublic IBinder onBind(Intent intent) {Log.e(TAG, "MainService onBind ");return new IRemoteServiceConn.Stub() {};}private ServiceConnection mServiceConnection = new ServiceConnection() {@Overridepublic void onServiceConnected(ComponentName name, IBinder service) {Log.e(TAG, "MainService onServiceConnected ");// 建立连接Toast.makeText(MainService.this, "onServiceConnected MainService建立连接到守护Service成功", Toast.LENGTH_LONG).show();}@Overridepublic void onServiceDisconnected(ComponentName name) {// 断开连接Log.e(TAG, "MainService onServiceDisconnected ");Intent guardIntent = new Intent(MainService.this, GuardService.class);startService(guardIntent);MainService.this.bindService(guardIntent,mServiceConnection, Context.BIND_IMPORTANT);}};
}
public class GuardService extends Service {private static final String TAG = "GuardService";private final int SERVICE_ID = 0x12;@Overridepublic void onCreate() {super.onCreate();Log.e(TAG, "GuardService 创建 onCreate: ");new Thread(() -> {while (true) {Log.e(TAG, "GuardService 等待接收消息");try {Thread.sleep(2000 * 20);} catch (InterruptedException e) {e.printStackTrace();}}}).start();}@RequiresApi(api = Build.VERSION_CODES.O)@Overridepublic int onStartCommand(Intent intent, int flags, int startId) {Log.e(TAG, "GuardService启动 onStartCommand: ");// 提高进程优先级startForeground(SERVICE_ID, Util.getNotification(GuardService.this, GuardService.class, "222", "2222"));// 绑定建立连接bindService(new Intent(this, MainService.class), mServiceConnection, Context.BIND_IMPORTANT);return START_STICKY;}@Nullable@Overridepublic IBinder onBind(Intent intent) {Log.e(TAG, "GuardService onBind ");return new IRemoteServiceConn.Stub() {};}private ServiceConnection mServiceConnection = new ServiceConnection() {@Overridepublic void onServiceConnected(ComponentName name, IBinder service) {Log.e(TAG, "GuardService onServiceConnected ");}@Overridepublic void onServiceDisconnected(ComponentName name) {Log.e(TAG, "GuardService onServiceDisconnected ");// 连接异常断开 ,重新启动,重新绑定Intent intent = new Intent(GuardService.this, MainService.class);startService(intent);bindService(intent,mServiceConnection, Context.BIND_IMPORTANT);}};
}

辅助类

public class Util {@RequiresApi(api = Build.VERSION_CODES.O)public static Notification getNotification(Context context, Class<?> cls, String title, String content) {Notification.Builder builder = new Notification.Builder(context); //获取一个Notification构造器if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {builder.setChannelId("notification_id");NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);NotificationChannel channel = new NotificationChannel("notification_id", "notification_name", NotificationManager.IMPORTANCE_LOW);notificationManager.createNotificationChannel(channel);}Intent nfIntent = new Intent(context, MainActivity.class);builder.setContentIntent(PendingIntent.getActivity(context, 0, nfIntent, 0)) // 设置PendingIntent.setLargeIcon(BitmapFactory.decodeResource(context.getResources(), R.mipmap.ic_launcher)) // 设置下拉列表中的图标(大图标).setContentTitle(title)// 设置下拉列表里的标题.setSmallIcon(R.mipmap.ic_launcher) // 设置状态栏内的小图标.setContentText(content) // 设置上下文内容.setWhen(System.currentTimeMillis()); // 设置该通知发生的时间Notification notification = builder.build(); // 获取构建好的Notificationnotification.defaults = Notification.DEFAULT_SOUND; //设置为默认的声音return notification;}
}

Service需要在清单文件声明

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"package="com.example.processgaurd"><uses-permission android:name="android.permission.FOREGROUND_SERVICE"/><applicationandroid:allowBackup="true"android:icon="@mipmap/ic_launcher"android:label="@string/app_name"android:roundIcon="@mipmap/ic_launcher_round"android:supportsRtl="true"android:theme="@style/Theme.LearnEassyJoke"><activity android:name=".MainActivity"><intent-filter><action android:name="android.intent.action.MAIN" /><category android:name="android.intent.category.LAUNCHER" /></intent-filter></activity><service android:name=".MainService" /><!--GuardService单独运行在一个进程--><serviceandroid:name=".GuardService"android:process=":guardService" /></application></manifest>

最后定义两个点击事件

    public void startService(View view) {startService(new Intent(this, MainService.class));}public void startRemoteService(View view) {startService(new Intent(this, GuardService.class));}

2.2执行流程

1.点击startService
2021-04-29 09:42:48.900 4323-4323/com.example.processgaurd E/MainService:  MainService 创建 onCreate:
2021-04-29 09:42:48.902 4323-4364/com.example.processgaurd E/MainService: MainService 等待接收消息
2021-04-29 09:42:48.902 4323-4323/com.example.processgaurd E/MainService:  MainService启动 onStartCommand: // 这一步虽然已经去bind了GuardService 但是GuardService没有启动 所以没有进一步的log2.点击startRemoteService
2021-04-29 09:42:51.187 1669-7737/system_process I/ActivityManager: Start proc 4380:com.example.processgaurd:guardService/u0a89 for service com.example.processgaurd/.GuardService
2021-04-29 09:42:51.234 4380-4380/com.example.processgaurd E/GuardService: GuardService 创建 onCreate:
2021-04-29 09:42:51.236 4380-4402/com.example.processgaurd E/GuardService: GuardService 等待接收消息
2021-04-29 09:42:51.238 4380-4380/com.example.processgaurd E/GuardService: GuardService onBind //MainService终于bind到了GuardService
2021-04-29 09:42:51.239 4380-4380/com.example.processgaurd E/GuardService: GuardService启动 onStartCommand: //GuardService启动并去bind到MainService
2021-04-29 09:42:51.242 4323-4323/com.example.processgaurd E/MainService: MainService onServiceConnected // MainService接收到成功绑定到GuardService的消息
2021-04-29 09:42:51.261 4323-4323/com.example.processgaurd E/MainService: MainService onBind //GuardService bind到了MainService
2021-04-29 09:42:51.264 4380-4380/com.example.processgaurd E/GuardService: GuardService onServiceConnected //GuardService接收到成功绑定到MainService的消息
这里看起来比较混乱 其实就是两个service相互bind 我们只需要知道一个Service的几个生命周期 以及ServiceConnection的两个回调,一切都很清晰:onCreate:service创建
onStartCommand:service启动
onBind:其他组件bind到本serviceonServiceConnected:本组件调用bindService之后 接收到service端bind成功的消息
onServiceDisconnected:本组件与其他service的bind异常终止

3. 使用JobService保活

关于JobService有一篇比较不错的文章
https://www.jianshu.com/p/8f9090e12015
注意 该方法只适用于低版本Android 且没有被Rom厂商修改framework代码的前提下,虽然网上很多文章说在Android7.0以上可以使用jobService进行保活 但是我没有测试成功(在Setting中点击强制停止 应用不会再次启动,但是使用adb kill -9的命令 进程可以被成功拉起),这里依然列举 是提一个思路以及学习一下JobSchedule JobService的使用

3.1 JobService的作用

JobSchedule通常和JobService结合起来使用 我们通常创建一个Service继承自JobService 然后实现onStartJob方法 我们通常在该Service的onStartCommand启动定时任务 onStartJob是定时任务的执行体(注意该执行体运行在主线程 因此耗时的操作需要另开线程处理)
JobService最初被设计出来的目的是让App做一些省电 省流量操作 比如,可以设置定时任务 该任务只在插入充电器的情况执行 或者该任务只在wifi连接的情况下进行。由于JobSchedule是将任务的处理抛给framework层处理,因此即时我们的应用被杀死,framework的任务也不会中断

3.2 Demo例子

配置自己的JobService

@RequiresApi(api = Build.VERSION_CODES.O)
public class MyJobService extends JobService {private static final int JOB_WAKE_UP_ID = 0x11;JobScheduler jobScheduler;int jobId;// 服务启动@Overridepublic int onStartCommand(Intent intent, int flags, int startId) {Log.e("hjcai", "onStartCommand: ");JobInfo.Builder jobBuilder = new JobInfo.Builder(JOB_WAKE_UP_ID, new ComponentName(this, MyJobService.class));if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {jobBuilder.setMinimumLatency(JobInfo.DEFAULT_INITIAL_BACKOFF_MILLIS); //执行的最小延迟时间jobBuilder.setOverrideDeadline(JobInfo.DEFAULT_INITIAL_BACKOFF_MILLIS);  //执行的最长延时时间jobBuilder.setMinimumLatency(JobInfo.DEFAULT_INITIAL_BACKOFF_MILLIS);jobBuilder.setBackoffCriteria(JobInfo.DEFAULT_INITIAL_BACKOFF_MILLIS, JobInfo.BACKOFF_POLICY_LINEAR);//线性重试方案} else {// 开启一个轮寻 每隔30秒查询jobBuilder.setPeriodic(JobInfo.DEFAULT_INITIAL_BACKOFF_MILLIS);}jobScheduler = (JobScheduler) getSystemService(Context.JOB_SCHEDULER_SERVICE);jobBuilder.setPersisted(true);  // 设置设备重启时,执行该任务jobId = jobScheduler.schedule(jobBuilder.build());return START_STICKY;}@Overridepublic boolean onStartJob(JobParameters params) {// 轮询的执行体// 看MainService有没有被杀死// 如果杀死了就重新启动Log.e("hjcai", "onStartJob: ");boolean messageServiceAlive = serviceAlive(GuardService.class.getName());if (!messageServiceAlive) {startForegroundService(new Intent(this, GuardService.class));}boolean messageServiceAlive2 = serviceAlive(MainService.class.getName());if (!messageServiceAlive2) {startForegroundService(new Intent(this, MainService.class));}jobFinished(params, false);// jobScheduler.cancel(jobId); //取消指定定时任务// jobScheduler.cancelAll(); //取消所有指定定时任务// Return true from this method if your job needs to continue running,the job remains active until you call jobFinished(android.app.job.JobParameters, boolean)return true;}/*** 判断某个服务是否正在运行的方法** @param serviceName 是包名+服务的类名(例如:net.loonggg.testbackstage.TestService)* @return true代表正在运行,false代表服务没有在运行*/private boolean serviceAlive(String serviceName) {boolean isWork = false;ActivityManager myAM = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);List<ActivityManager.RunningServiceInfo> myList = myAM.getRunningServices(100);if (myList.size() <= 0) {return false;}for (int i = 0; i < myList.size(); i++) {String mName = myList.get(i).service.getClassName();if (mName.equals(serviceName)) {isWork = true;break;}}Log.e("hjcai", "serviceAlive: isWork " + isWork);return isWork;}@Overridepublic boolean onStopJob(JobParameters params) {return false;}
}

在系统清单文件配置service以及权限

    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" /><serviceandroid:name=".MyJobService"android:enabled="true"android:process=":jobService"android:permission="android.permission.BIND_JOB_SERVICE" />

在合适的时机启动该Service

    public void startJobService(View view) {startService(new Intent(this, MyJobService.class));}

该Service启动后 过一段时间就会查询所有Service 查看指定Service是否存活,如果不是存活状态 将其启动以达到保活的目的。

红橙Darren视频笔记 App保活-双进程守护与JobService相关推荐

  1. 红橙Darren视频笔记 UML图简介

    整体架构复制自红橙原视频的课堂笔记 因为他这一课没有博客,所以没有转载链接,CSDN没有转载地址是无法作为转载类型的文章发表的,暂时标记为原创 参考链接 https://blog.csdn.net/r ...

  2. 红橙Darren视频笔记 类加载机制(API28) 自己写个热修复 查看源码网站

    第一部分 类加载机制 一个Activity是如何被Android虚拟机找到的? 在之前的文章 红橙Darren视频笔记 自定义View总集篇(https://blog.csdn.net/u011109 ...

  3. 红橙Darren视频笔记 Behavior的工作原理源码分析

    主要coordinatorlayout的代码来自coordinatorlayout-1.0.0-sources.jar 本文从源码介绍 CoordinatorLayout 的 behavior 怎么工 ...

  4. 红橙Darren视频笔记 ViewGroup事件分发分析 基于API27

    本节目标,通过案例,先看程序运行结果,然后跟踪源码,理解为什么会有这样的输出,继而理解view group的分发机制,感觉和证明题很像呢. 考虑以下程序的运行结果: case1: public cla ...

  5. 红橙Darren视频笔记 代理模式 动态代理和静态代理

    红橙Darren视频笔记 代理模式 动态代理和静态代理(Android API 25) 关于代理模式我之前有过相关的介绍: https://blog.csdn.net/u011109881/artic ...

  6. 红橙Darren视频笔记 利用阿里巴巴AndFix进行热修复

    注意 由于AndFix在2017年左右就停止更新了,在最新版本的apk上遇到很多问题,我最终也没有成功进行热修复.本节主要是学习热修复的原理 在上一篇 红橙Darren视频笔记 自己捕获异常并保存到本 ...

  7. 红橙Darren视频笔记 仿QQ侧滑效果

    这一篇没有什么新的内容 就是改写 红橙Darren视频笔记 仿酷狗侧滑效果 的侧滑的效果 1.去掉淡入淡出效果 2.加上黑色模板效果 效果: 去掉淡入淡出效果很简单 就是注释掉onScrollChan ...

  8. Android进程保活——双进程守护

    作为一名知乎重度使用患者,前几天刷知乎的时候,看到一篇帖子. 怎么让 Android 程序一直后台运行,像 QQ 一样不被杀死? 这样的一款手机应用,就一流氓软件,后台一直有service在跑着,如果 ...

  9. 红橙Darren视频笔记 view的绘制流程(上) onMeasure测量代码分析 基于API27

    一.准备工作Activity的onCreate和onResume调用过程 从ActivityThread的handleLaunchActivity开始进行代码跟踪 private void handl ...

最新文章

  1. PHP 配置文件详解(php.ini 详解 )
  2. JVM锁和分布式锁是什么关系
  3. Java web对试卷进行单选多选答题进行打分_2020年大学慕课Java程序设计作业答案...
  4. 用友t3服务器文件丢失,用友T3软件在T3用友通标准版恢复账套时在备份的文件中找不到要恢复的文件,如何解决?-用友T3...
  5. 设计模式系列漫谈之二 - 工厂方法模式
  6. 如何使用java代码生成_使用Java成功生成代码的7个技巧
  7. 工作几年了,原来我只用了数据校验的皮毛
  8. python document_python-docx 常用方法
  9. linux根目录cdef,关于linux:Cython:从python调用的cdef函数中调用扩展类型cdef方法...
  10. 真·不怪云原生:探寻IT大厂逐渐云化的秘密!
  11. 7-8 mmh学长的Excel表格 (20分)
  12. Wireguard笔记
  13. 华为USG6000V 多ISP接入Internet(基于ISP目的地址的多出口)
  14. cad转pdf怎么变成黑白?
  15. 二、帧模式 MPLS 操作
  16. 信息提取(Information Extraction)
  17. Android第三方框架之学习高德地图SDK-----①集成环境,获取定位信息,地图显示。
  18. WIN10教育版激活方法
  19. Glyphs for Mac 2.6.5 — 字体设计工具
  20. 联想笔记本电脑w530更换电池的电芯并进行软件重置,不再提示更换电池

热门文章

  1. c语言如何打印unicode字符,如何在C ++中打印Unicode字符?
  2. foreach和while的区别(编译之后)_C++学习大纲:条件编译
  3. 恋舞ol服务器维护中,【公告】《恋舞OL》5月20日更新维护公告
  4. 回炉重造-数据结构之数组列表
  5. 5分钟速成C++14多线程编程
  6. 一些移动端的ui框架
  7. java第六次作业 计科1501班 张鹏
  8. ansible之二:模块用法
  9. 2014年自动化的个人感想
  10. 有关锁和内存使用的DMV