(十六)Android 进程保活

版权声明:本文为博主原创文章,未经博主允许不得转载。
本文纯个人学习笔记,由于水平有限,难免有所出错,有发现的可以交流一下。

一、进程的优先级

Android 系统将尽量长时间地保持应用进程,但为了新建进程或运行更重要的进程,需要清除旧进程来回收内存。 为了确定保留或终止哪些进程,系统会对进程进行分类。 需要时,系统会首先消除重要性最低的进程,然后是清除重要性稍低一级的进程,依此类推,以回收系统资源。

进程的重要性层次结构一共有 6 级:(官方文档只写 5 级)
在这里插入图片描述

1.前台进程(foreground)

用户当前操作所必需的进程。如果一个进程满足以下任一条件,即视为前台进程:

  • 托管用户正在交互的 Activity(已调用 Activity 的 onResume() 方法)
  • 托管某个 Service,后者绑定到用户正在交互的 Activity
  • 托管正在“前台”运行的 Service(服务已调用 startForeground())
  • 托管正执行一个生命周期回调的 Service(onCreate()、onStart() 或 onDestroy())
  • 托管正执行其 onReceive() 方法的 BroadcastReceiver

通常,在任意给定时间前台进程都为数不多。只有在内存不足以支持它们同时继续运行这一万不得已的情况下,系统才会终止它们。 此时,设备往往已达到内存分页状态,因此需要终止一些前台进程来确保用户界面正常响应。

2.可见进程(visible)

没有任何前台组件、但仍会影响用户在屏幕上所见内容的进程。 如果一个进程满足以下任一条件,即视为可见进程:

  • 托管不在前台、但仍对用户可见的 Activity(已调用其 onPause() 方法)。例如,如果前台 Activity 启动了一个对话框,允许在其后显示上一 Activity,则有可能会发生这种情况。
  • 托管绑定到可见(或前台)Activity 的 Service。

可见进程被视为是极其重要的进程,除非为了维持所有前台进程同时运行而必须终止,否则系统不会终止这些进程。

3.服务进程(secondary server)

正在运行已使用 startService() 方法启动的服务且不属于上述两个更高类别进程的进程。尽管服务进程与用户所见内容没有直接关联,但是它们通常在执行一些用户关心的操作(例如,在后台播放音乐或从网络下载数据)。因此,除非内存不足以维持所有前台进程和可见进程同时运行,否则系统会让服务进程保持运行状态。

4.后台进程(hidden)

包含目前对用户不可见的 Activity 的进程(已调用 Activity 的 onStop() 方法)。这些进程对用户体验没有直接影响,系统可能随时终止它们,以回收内存供前台进程、可见进程或服务进程使用。 通常会有很多后台进程在运行,因此它们会保存在 LRU (最近最少使用)列表中,以确保包含用户最近查看的 Activity 的进程最后一个被终止。如果某个 Activity 正确实现了生命周期方法,并保存了其当前状态,则终止其进程不会对用户体验产生明显影响,因为当用户导航回该 Activity 时,Activity 会恢复其所有可见状态。 有关保存和恢复状态的信息,请参阅 Activity文档。

5.内容供应节点(content provider)

没有程序实体,进提供内容供别的程序去用的,比如日历供应节点,邮件供应节点等。在终止进程时,这类程序应该有较高的优先权。

6.空进程(empty)

不含任何活动应用组件的进程。保留这种进程的的唯一目的是用作缓存,以缩短下次在其中运行组件所需的启动时间。 为使总体系统资源在进程缓存和底层内核缓存之间保持平衡,系统往往会终止这些进程。

具体可以查看安卓官方中文网相关内容

二、进程释放

1.Low Memory Killer

系统出于体验和性能上的考虑,app 在退到后台时系统并不会真正的 kill 掉这个进程,而是将其缓存起来。打开的应用越多,后台缓存的进程也越多。

在系统内存不足的情况下,系统开始依据自身的一套进程回收机制来判断要 kill 掉哪些进程,以腾出内存来供给需要的 app, 这套杀进程回收内存的机制就叫 Low Memory Killer。

查看阈值指令:

cat /sys/module/lowmemorykiller/parameters/minfree

这个结果是6个数字,以逗号隔开,如:
在这里插入图片描述

这 6 个值分别对应上面 6 级进程的的阈值。单位是 page, 1 page 为 4 个 KB,如最后一个为 46080 * 4 = 184320 KB,为 180 MB。当内存少于 180 MB 的时候,会进行回收空进程所占用的内存。

内存阈值在不同的手机上不一样,一旦低于该值,Android 便开始按顺序关闭进程。

2.oom_adj

进程的优先级通过进程的 adj 值来反映,它是 linux 内核分配给每个系统进程的一个值,进程回收机制根据这个值来决定是否进行回收。adj 的值越小,进程的优先级越高。

查看当前进程的 adj 值(需要 root 权限):

cat /proc/进程 id/oom_adj

应用正在运行:
在这里插入图片描述

按 Home 键隐藏后(不同的ROM可能不一样):
在这里插入图片描述

进程 id 可以直接通过开发工具查看:
在这里插入图片描述

adj 值的解释:
在这里插入图片描述

adj 越大,占用内存越多会被先被 kill 掉,所以保活就成了降低 oom_adj 的值,以及如何使得我们应用占的内存最少。

三、提权

由上面分析可以知道,在内存不足的时候,安卓系统会根据应用程序的 adj 来判断释放程序的先后顺序,为了使我们的应用更久的运行在安卓系统中,我们可以通过一些方法使应用的 adj 尽可能的变小,这样就可以尽可能的晚一点被释放,甚至不被释放。

1.Activity 提权

监控手机锁屏解锁事件,在屏幕锁屏时启动 1 个像素透明的 Activity,在用户解锁时将 Activity 销毁掉。从而达到在锁屏时候提高进程优先级的作用。

我们新建一个大小只有 1 个像素的 Activity。

KeepActivity:

public class KeepActivity extends Activity {

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        Window window = getWindow();

        //设置这个 Activity 在左上角
        window.setGravity(Gravity.START | Gravity.TOP);
        WindowManager.LayoutParams attributes = window.getAttributes();
        attributes.width = 1;
        attributes.height = 1;
        attributes.x = 0;
        attributes.y = 0;
        window.setAttributes(attributes);
        
        //保存当前 activity,释放的时候需要使用
        KeepManager.getInstance().setKeep(this);
    }
}

在 AndroidManifest.xml 中配置这个 activity 在最近列表不显示,以及新建堆栈堆栈保存该 Activity。设置样式窗口背景为空并且透明。

AndroidManifest.xml

        <!-- android:excludeFromRecents 设置在最近列表中不显示 -->
        <!-- android:taskAffinity 设置新建堆栈保存该 Activity,
            不指定新的堆栈,在息屏亮屏后,改应用会自动显示出来 -->
        <activity android:name=".activity.KeepActivity"
            android:excludeFromRecents="true"
            android:taskAffinity="com.xiaoyue.myapplication.activity.KeepActivity"
            android:theme="@style/KeepTheme">
        </activity>

styles.xml:

    <!-- 提权 Activity Style -->
    <style name="KeepTheme">
        <!-- 添加窗口背景为空 -->
        <item name="android:windowBackground">@null</item>
        <!-- 添加窗口为透明的 -->
        <item name="android:windowIsTranslucent">true</item>
    </style>

新建 KeepActivity 的管理类 KeepManager,管理 Activity 提权时的广播注册与反注册,Activity 的启动与释放。
KeepManager:

public class KeepManager {

    private WeakReference<Activity> mKeepAct;
    private KeepReceiver mKeepReceiver;
    private static final KeepManager ourInstance = new KeepManager();

    public static KeepManager getInstance() {
        return ourInstance;
    }

    private KeepManager() {
    }

    /**
     * 注册息屏亮屏广播
     * @param context
     */
    public void registerKeep(Context context) {
        IntentFilter filter = new IntentFilter();
        filter.addAction(Intent.ACTION_SCREEN_OFF);
        filter.addAction(Intent.ACTION_SCREEN_ON);
        mKeepReceiver = new KeepReceiver();
        context.registerReceiver(mKeepReceiver, filter);
    }

    /**
     * 反注册广播接收者
     * @param context
     */
    public void unregisterKeep(Context context) {
        if (null != mKeepReceiver) {
            context.unregisterReceiver(mKeepReceiver);
        }
    }

    /**
     * 开启 Activity
     * @param context
     */
    public void startKeep(Context context) {
        Intent intent = new Intent(context, KeepActivity.class);
        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        context.startActivity(intent);
    }

    /**
     * 结束 Activity
     */
    public void finishKeep() {
        if (null != mKeepAct) {
            Activity activity = mKeepAct.get();
            if (null !&
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值