点击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 杀进程标准
屏幕熄灭的时候 启动一个 1px Activity ,在灭屏的时候关闭,提高进程的优先级,进程保活【具体看源码实现】
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);
}
}
});
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);
}
});
成活率是最高的 上面几种 双服务+ 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模拟现象:
5. 广播拉活, 比如自家的2个APP,自定义广播
6. 厂商推送拉活
参考: https://blog.csdn.net/ck15221693760/article/details/94391699
源码地址:https://download.csdn.net/download/dreams_deng/12438758
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();
});
}
}