Android 进程保活,点击home键 或者 点击back键盘 、锁屏、息屏保证服务器定时器不会阻塞

点击home键 或者 点击back键盘 、锁屏、息屏,保活,保证定时器不会被阻塞,如果用户直接杀死App,那么无法保活

 进程保护状态:
  android 进程优先级:
https://www.cnblogs.com/lixiansheng/p/11359937.html
 前台进程
 可视进程: activy有弹框
 服务进程: activity退出,后台服务在运行
 后台进程:  没有服务,activity退出
 空进程

 **进程管理策略:
进程启动分为 冷启动和热启动  
 热启动:当用户退出某一个进程的时候,并不会真正的进程退出,而是把这个进程放入后台,已便下次启动的时候可以马上启动起来,
 这个是 Android设置理念之一,  这个机制带来问题, 每个进程都有自己独立内存,打开数量增多,系统内存越来越大,导致系统内存不足,
 解决:   系统引入 LowmemoryKiller(简称:lmk)  来管理所有进程, 根据一定策略kill某个进程 释放占用内存,保证系统正常运行

 ** LMK 基本原理
 所有进程都是从zygote 孵化出来的, 记录在AMS的 mLruProcess 列表中, 由于AMS统一 管理, 
AMS 中会根据 进程状态更新进程的 oom_odj 值 ,这个值会传递到 kernel中, kernel中 有 低内存回收机制,
在内存 达到一定阀 值的时候触发 清理 oom_odj值 腾出更多空间  

**  LMK 杀进程标准

1. 1px Activity

屏幕熄灭的时候 启动一个 1px Activity ,在灭屏的时候关闭,提高进程的优先级,进程保活【具体看源码实现】

2.    前台Service startForeground, 提高service 的服务的优先级

ForegroundService.java文件 
package ndkdemo.denganzhi.com.myapplication.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.Handler;
import android.os.IBinder;
import android.support.annotation.Nullable;
import android.support.v4.app.NotificationCompat;
import android.util.Log;

/**
 * @author Damon
 * @Date 2019/5/30 22:45
 */
public class ForegroundService extends Service {
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    private static final String TAG = "ForegroundService";
    final Handler mHandler = new Handler();
    Runnable r = new Runnable() {
        @Override
        public void run() {
             Log.e(TAG,"ForegroundService-->定时器在运行......");
            //do something
            //每隔1s循环执行run方法
            mHandler.postDelayed(this, 1000);
        }
    };


    @Override
    public void onCreate() {
        super.onCreate();
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            NotificationChannel channel = new NotificationChannel("deamon", "deamon",
                    NotificationManager.IMPORTANCE_LOW);
            NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
            if (manager == null)
                return;
            manager.createNotificationChannel(channel);

            Notification notification = new NotificationCompat.Builder(this, "deamon").setAutoCancel(true).setCategory(
                    Notification.CATEGORY_SERVICE).setOngoing(true).setPriority(
                    NotificationManager.IMPORTANCE_LOW).build();
            startForeground(10, notification);
        } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
            //如果 18 以上的设备 启动一个Service startForeground给相同的id
            //然后结束那个Service
            // 结果 启动 ForegroundService  关闭通知
            startForeground(10, new Notification());
            startService(new Intent(this, InnnerService.class));
        } else {
            /**
             * 在API18以下,直接调用startForeground(ID, new Notification()),发送空的Notification ,将后台服务推到前台成为前台Service,这样即使退出应用,或者在Recent Task中删除该应用,前台Service依然存在,应用的优先级依然很高
             * 这样能实现的原理其实是Android的一个漏洞,发送一个空的Notification,通知栏并不会显示我们发送的Notification,这样用户就不知道你的应用还是在运行了,真正的做到了用户无感知下的进程保活
             */
            startForeground(10, new Notification());
        }


        //主线程中调用:
        mHandler.postDelayed(r, 100);//延时100毫秒

    }

    public static class InnnerService extends Service {

        @Override
        public void onCreate() {
            super.onCreate();
            startForeground(10, new Notification());
            stopSelf();
        }

        @Nullable
        @Override
        public IBinder onBind(Intent intent) {
            return null;
        }
    }
}

配置文件: 


启动前台服务: 

btn1.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
             //   2.    前台Service, 提高service 的服务的优先级
                Intent service=new Intent(MainActivity.this,ForegroundService.class);
                if (Build.VERSION.SDK_INT >= 26) {
                    startForegroundService(service);
                } else {
                    startService(service);
                }

            }
        });

3.   JobScheduler 使用   就是一个定时器

package ndkdemo.denganzhi.com.myapplication.jobscheduler;

import android.annotation.SuppressLint;
import android.app.job.JobInfo;
import android.app.job.JobParameters;
import android.app.job.JobScheduler;
import android.app.job.JobService;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.os.IBinder;
import android.support.annotation.Nullable;
import android.support.annotation.RequiresApi;
import android.util.Log;

import java.util.Date;

/***
 *  就是一个定时器
 */
@SuppressLint("NewApi")
public class MyJobService extends JobService {
    private static final String TAG = "MyJobService";

    public static void startJob(Context context) {
        JobScheduler jobScheduler = (JobScheduler) context.getSystemService(
                Context.JOB_SCHEDULER_SERVICE);
        JobInfo.Builder builder = new JobInfo.Builder(10,
                new ComponentName(context.getPackageName(),
                        MyJobService.class.getName())).setPersisted(true);
        /**
         * I was having this problem and after review some blogs and the official documentation,
         * I realised that JobScheduler is having difference behavior on Android N(24 and 25).
         * JobScheduler works with a minimum periodic of 15 mins.
         * android7 以后
         *
         */
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N){
            //7.0以上延迟1s执行, api 调用
            builder.setMinimumLatency(1000);
        }else{
            //每隔1s执行一次job
            builder.setPeriodic(1000);
        }
        jobScheduler.schedule(builder.build());
    }

    @Override
    public boolean onStartJob(JobParameters jobParameters) {
        Log.e(TAG,"开启job:"+ new Date());
        //7.0以上轮询
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N){
            startJob(this);
        }

        return false;
    }

    @Override
    public boolean onStopJob(JobParameters jobParameters) {
        return false;
    }
}

 配置文件: 

 
      
  
 

 启动JobSchduleService:  

 btn2.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
            //     3.   JobScheduler 使用   就是一个定时器
                MyJobService.startJob(MainActivity.this);
            }
        });


4.  双进程守护 

成活率是最高的 上面几种   双服务+ JobSchdule

 LocalService.java   A 服务, A 绑定B 服务,监听到 B服务 onServiceDisconnected ,重新启动B 服务

package ndkdemo.denganzhi.com.myapplication.twoservice;

import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.Service;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Build;
import android.os.Handler;
import android.os.IBinder;
import android.os.RemoteException;
import android.support.annotation.Nullable;
import android.support.v4.app.NotificationCompat;
import android.util.Log;

import ndkdemo.denganzhi.com.myapplication.IMyAidlInterface;


public class LocalService extends Service {
    private MyBinder myBinder;

    private static final String TAG = "twoservice";

    final Handler mHandler = new Handler();
    Runnable r = new Runnable() {
        @Override
        public void run() {
            Log.e(TAG,"LocalService-->定时器在运行......");
            //do something
            //每隔1s循环执行run方法
            mHandler.postDelayed(this, 1000);
        }
    };


    class MyBinder extends IMyAidlInterface.Stub{

        @Override
        public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
                               double aDouble, String aString) throws RemoteException {

        }
    }
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return myBinder;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        myBinder = new MyBinder();
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            NotificationChannel channel = new NotificationChannel("deamon", "deamon",
                    NotificationManager.IMPORTANCE_LOW);
            NotificationManager manager = (NotificationManager) getSystemService(
                    Context.NOTIFICATION_SERVICE);
            if (manager == null)
                return;
            manager.createNotificationChannel(channel);

            Notification notification = new NotificationCompat.Builder(this,
                    "deamon").setAutoCancel(true).setCategory(
                    Notification.CATEGORY_SERVICE).setOngoing(true).setPriority(
                    NotificationManager.IMPORTANCE_LOW).build();
            startForeground(10, notification);
        } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
            //如果 18 以上的设备 启动一个Service startForeground给相同的id
            //然后结束那个Service
            startForeground(10, new Notification());
            startService(new Intent(this, InnnerService.class));
        } else {
            startForeground(10, new Notification());
        }
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {

        //主线程中调用:
        mHandler.postDelayed(r, 100);//延时100毫秒

        bindService(new Intent(this, RemoteService.class), new MyServiceConnection(),
                BIND_AUTO_CREATE);
        return super.onStartCommand(intent, flags, startId);
    }

    private class MyServiceConnection implements ServiceConnection {

        @Override
        public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
            //回调

        }

        @Override
        public void onServiceDisconnected(ComponentName componentName) {
            //
            startService(new Intent(LocalService.this, RemoteService.class));
            bindService(new Intent(LocalService.this, RemoteService.class), new MyServiceConnection(),
                    BIND_AUTO_CREATE);
        }
    }

    public static class InnnerService extends Service {

        @Override
        public void onCreate() {
            super.onCreate();
            startForeground(10, new Notification());
            stopSelf();
        }

        @Nullable
        @Override
        public IBinder onBind(Intent intent) {
            return null;
        }
    }
}

 RemoteService .java   B 服务,B 绑定 A服务,监听到 A 服务 onServiceDisconnected ,重新启动 A服务

package ndkdemo.denganzhi.com.myapplication.twoservice;

import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.Service;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Build;
import android.os.Handler;
import android.os.IBinder;
import android.os.RemoteException;
import android.support.annotation.Nullable;
import android.support.v4.app.NotificationCompat;
import android.util.Log;

import ndkdemo.denganzhi.com.myapplication.IMyAidlInterface;


public class RemoteService extends Service {
    private MyBinder myBinder;


    private static final String TAG = "twoservice";

    final Handler mHandler = new Handler();
    Runnable r = new Runnable() {
        @Override
        public void run() {
            Log.e(TAG,"RemoteService-->定时器在运行......");
            //do something
            //每隔1s循环执行run方法
            mHandler.postDelayed(this, 1000);
        }
    };

    class MyBinder extends IMyAidlInterface.Stub {

        @Override
        public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
                               double aDouble, String aString) throws RemoteException {

        }
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return myBinder;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        myBinder = new MyBinder();
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            NotificationChannel channel = new NotificationChannel("deamon", "deamon",
                    NotificationManager.IMPORTANCE_LOW);
            NotificationManager manager = (NotificationManager) getSystemService(
                    Context.NOTIFICATION_SERVICE);
            if (manager == null)
                return;
            manager.createNotificationChannel(channel);

            Notification notification = new NotificationCompat.Builder(this,
                    "deamon").setAutoCancel(true).setCategory(
                    Notification.CATEGORY_SERVICE).setOngoing(true).setPriority(
                    NotificationManager.IMPORTANCE_LOW).build();
            startForeground(10, notification);
        } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
            //如果 18 以上的设备 启动一个Service startForeground给相同的id
            //然后结束那个Service
            startForeground(10, new Notification());
            startService(new Intent(this, InnnerService.class));
        } else {
            startForeground(10, new Notification());
        }
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        bindService(new Intent(this, LocalService.class), new MyServiceConnection(),
                BIND_AUTO_CREATE);

        //主线程中调用:
        mHandler.postDelayed(r, 100);//延时100毫秒

        return super.onStartCommand(intent, flags, startId);
    }

    private class MyServiceConnection implements ServiceConnection {

        @Override
        public void onServiceConnected(ComponentName componentName, IBinder iBinder) {

        }

        @Override
        public void onServiceDisconnected(ComponentName componentName) {
            startService(new Intent(RemoteService.this, LocalService.class));
            // 当服务死了,断开,重新互相绑定, 重新唤醒服务
            bindService(new Intent(RemoteService.this, LocalService.class),
                    new MyServiceConnection(), BIND_AUTO_CREATE);
        }
    }

    public static class InnnerService extends Service {

        @Override
        public void onCreate() {
            super.onCreate();
            startForeground(10, new Notification());
            stopSelf();
        }

        @Nullable
        @Override
        public IBinder onBind(Intent intent) {
            return null;
        }
    }
}

StartMyJobService.java JobSchdule中监听服务是否被杀死,如果服务不在了启动服务,3向保证

package ndkdemo.denganzhi.com.myapplication.twoservice;

import android.annotation.SuppressLint;
import android.app.ActivityManager;
import android.app.job.JobInfo;
import android.app.job.JobParameters;
import android.app.job.JobScheduler;
import android.app.job.JobService;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.text.TextUtils;
import android.util.Log;

import java.util.List;



@SuppressLint("NewApi")
public class StartMyJobService extends JobService {
    private static final String TAG = "twoservice";

    public static void startJob(Context context) {
        JobScheduler jobScheduler = (JobScheduler) context.getSystemService(
                Context.JOB_SCHEDULER_SERVICE);
        JobInfo.Builder builder = new JobInfo.Builder(10,
                new ComponentName(context.getPackageName(),
                        StartMyJobService.class.getName())).setPersisted(true);
        /**
         * I was having this problem and after review some blogs and the official documentation,
         * I realised that JobScheduler is having difference behavior on Android N(24 and 25).
         * JobScheduler works with a minimum periodic of 15 mins.
         *
         */
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            //7.0以上延迟1s执行
            builder.setMinimumLatency(1000);
        } else {
            //每隔1s执行一次job
            builder.setPeriodic(1000);
        }
        jobScheduler.schedule(builder.build());
    }

    @Override
    public boolean onStartJob(JobParameters jobParameters) {
        Log.e(TAG, "StartMyJobService-->开启job");
        //7.0以上轮询
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            startJob(this);
        }
        //判断服务是否在运行
        boolean isLocalServiceRun = isServiceRunning(this, LocalService.class.getName());
        boolean isRemoteServiceRun = isServiceRunning(this, RemoteService.class.getName());
        // 在jdbschdule 中如果服务死了,立刻拉活
        if (!isLocalServiceRun || !isRemoteServiceRun) {

            startService(new Intent(this, LocalService.class));
            startService(new Intent(this, RemoteService.class));
        }
        return false;
    }

    private boolean isServiceRunning(Context context, String serviceName) {
        ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
        List runningServices = am.getRunningServices(10);
        for (ActivityManager.RunningServiceInfo runningService : runningServices) {
            if (TextUtils.equals(runningService.service.getClassName(), serviceName)) {
                return true;
            }
        }

        return false;
    }

    @Override
    public boolean onStopJob(JobParameters jobParameters) {
        return false;
    }
}

IMyAidlInterface.aidl

// IMyAidlInterface.aidl
package ndkdemo.denganzhi.com.myapplication;

// Declare any non-default types here with import statements

interface IMyAidlInterface {
    /**
     * Demonstrates some basic types that you can use as parameters
     * and return values in AIDL.
     */
    void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
            double aDouble, String aString);
}

 启动A,B 服务,启动JobSchdule:

       btn3.setOnClickListener(new View.OnClickListener() {
           @Override
           public void onClick(View v) {

               //  4.  双进程  成活率是最高的
               startService(new Intent(MainActivity.this, LocalService.class));
               startService(new Intent(MainActivity.this, RemoteService.class));
               StartMyJobService.startJob(MainActivity.this);
           }
       });

Android  Studio模拟现象:

Android 进程保活,点击home键 或者 点击back键盘 、锁屏、息屏保证服务器定时器不会阻塞_第1张图片

5.  广播拉活, 比如自家的2个APP,自定义广播
6.  厂商推送拉活

 参考: https://blog.csdn.net/ck15221693760/article/details/94391699

 源码地址:https://download.csdn.net/download/dreams_deng/12438758

 

5.  闹钟

 alarmManager 是一个全局定时器 ,可以在指定时间或 指定周期 启动其他组件 Activity,Service,broadReciver , 不仅仅是闹钟,但是实际没有什么软用
package com.denganzhi.guestmodel;

import android.app.AlarmManager;
import android.app.PendingIntent;
import android.app.TimePickerDialog;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.Button;
import android.widget.Toast;

import java.util.Calendar;

public class NaoZhongActivity extends AppCompatActivity {
    private AlarmManager aManager;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_nao_zhong);

        // 获取AlarmManager对象
        aManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
        // 获取程序界面上的按钮
        Button setTimeBn = findViewById(R.id.setTime);
        // 为“设置闹铃”按钮绑定监听器
        setTimeBn.setOnClickListener(view -> {
            Calendar currentTime = Calendar.getInstance();
            // 创建一个TimePickerDialog实例,并把它显示出来
            new TimePickerDialog(NaoZhongActivity.this, 0, // 绑定监听器
                    (dialog, hourOfDay, minute) -> {
                        // 指定启动AlarmActivity组件
                        // 这里可以启动一个 Activity ,比如播放音乐
                        Intent intent = new Intent(NaoZhongActivity.this, AlarmActivity.class);
                        // 创建PendingIntent对象
                        PendingIntent pi = PendingIntent.getActivity(NaoZhongActivity.this, 0, intent, 0);
                        Calendar c = Calendar.getInstance();
                        // 根据用户选择时间来设置Calendar对象
                        c.set(Calendar.HOUR_OF_DAY, hourOfDay);
                        c.set(Calendar.MINUTE, minute);
                        // 设置AlarmManager将在Calendar对应的时间启动指定组件
                        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { // 6.0及以上
                            /***
                             *  alarmManager 是一个全局定时器 ,可以在指定时间或 指定周期 启动其他组件 Activity,Service,broadReciver
                             *
                             * set(@AlarmType int type, long triggerAtMillis, PendingIntent operation) {
                             *         setImpl(type, triggerAtMillis, legacyExactLength(), 0, 0, operation, null, null,
                             *                 null, null, null)
                             *
                             *  type:枚举,
                             *      AlarmManager.ELAPSED_REALTIME:
                             *      执行从现在开始 时间 过了 一定时间 后启动 operate对应组件
                             *         AlarmManager.ELAPSED_REALTIME_WAKEUP:
                             *          上面 的扩展 即使 系统处于 休眠状态
                             *
                             *     RTC_WAKEUP :  指定系统 调用 System.currentTimeMillis() 方法的 返回值 与  triggerAtMillis 相等时
                             *     启动 pi 对应组件 , 系统处于休眠状态 也会执行 即使
                             *
                             */


                            aManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP,
                                    c.getTimeInMillis(), pi);
                        } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { // 4.4及以上
                            aManager.setExact(AlarmManager.RTC_WAKEUP, c.getTimeInMillis(), pi);
                        }
                        else {
                            aManager.set(AlarmManager.RTC_WAKEUP, c.getTimeInMillis(), pi);
                        }


                        /**
                         * setInexactRepeating (@AlarmType int type, long triggerAtMillis,
                         *             long intervalMillis, PendingIntent operation)
                         *             每小时启动过一次 比如
                         *  setRepeating(@AlarmType int type, long triggerAtMillis,
                         *             long intervalMillis, PendingIntent operation)
                         *             设置一个周期定时任务
                         *
                         */

                        // 显示闹铃设置成功的提示信息
                        Toast.makeText(NaoZhongActivity.this, "闹铃设置成功啦",
                                Toast.LENGTH_SHORT).show();
                    },currentTime.get(Calendar.HOUR_OF_DAY),
                    currentTime.get(Calendar.MINUTE), false).show();
        });

    }
}

 

你可能感兴趣的:(Android开发)