高德应用后台持续定位【AIDL双进程service保活实现方法+一像素综合方案】后续增加15s杀死不启动保活,15S后杀死启动保活功能,在最下面

应用后台持续定位:官方说明

单页面单次/连续定位切换:官方说明

获取地址描述数据【地址转坐标】【地址转坐标】:官方说明

获取两条经纬度线段的交点坐标工具类

ScheduledExecutorService 实现定时任务


如果打算使用定时器的话,可以使用ScheduledExecutorService替换Timer,这个更好用!


本地进程 

/**
 * Author : 马占柱
 * E-mail : mazhanzhu_3351@163.com
 * Time   : 2021/6/5 20:34
 * Desc   : 本地进程
 */
public class LocalService extends Service {
    public static final String TAG = "守护进程";
    private MediaPlayer mediaPlayer = null;
    private MyBuilder myBuilder;
    private ScheduledExecutorService threadPool = null;
    private AMapLocationClient mClient;
    private ScreenReceiverUtil mScreenListener;
    private ScreenManager mScreenManager;
    private final int MSGWHAT = 19;
    private Handler handler = new Handler(Looper.getMainLooper()) {
        @Override
        public void handleMessage(@NonNull Message msg) {
            super.handleMessage(msg);
            if (msg.what == MSGWHAT) {
                ThreadPoolUtils.execute(new Runnable() {
                    @Override
                    public void run() {
                        Http_Tens.postService(null, LocalService.class.getName());
                    }
                });
                handler.sendEmptyMessageDelayed(MSGWHAT, 1000 * 10);
            }
        }
    };

    public LocalService() {
    }

    @Override
    public void onCreate() {
        super.onCreate();
        if (myBuilder == null) {
            myBuilder = new MyBuilder();
        }
        mScreenListener = new ScreenReceiverUtil(this);//注册锁屏广播监听器
        mScreenManager = ScreenManager.getInstance(this);
        mScreenListener.setScreenReceiverListener(mScreenListenerer);
        initGD();
    }

    //这里,只是使用一下连续定位,因为单次定位的话,会导致手机状态栏上面定位图标一直闪,影响体验
    private void initGD() {
        mClient = new AMapLocationClient(App.getContext());
        AMapLocationClientOption mLocationOption = new AMapLocationClientOption();
        mLocationOption.setOnceLocation(false);
        mLocationOption.setInterval(1000 * 3);//默认连续定位是2s,高德APP设置的是1S
        mClient.setLocationOption(mLocationOption);
        mClient.setLocationListener(new AMapLocationListener() {
            @Override
            public void onLocationChanged(AMapLocation aMapLocation) {
                Log_Ma.e(TAG, "------1111-----------" + aMapLocation.toString());
                if (aMapLocation != null && aMapLocation.getErrorCode() == 0) {
                    initAmap(aMapLocation);
                } else {
                    WeiLan_GaoDe.getInstance().initOneLocation(App.getContext(), new WeiLan_GaoDe.OneListener() {
                        @Override
                        public void succeed(AMapLocation loc) {
                            initAmap(loc);
                        }

                        @Override
                        public void onError() {
                            PowerManagerUtil.getInstance().awakening(LocalService.this);
                        }
                    });
                }
            }
        });
        mClient.startLocation();
    }

    private void initAmap(AMapLocation loc) {
        MMKV.defaultMMKV().putString(Constant.AMapLocation_Time, loc.getTime() + "");
        MMKV.defaultMMKV().putString(Constant.AMapLocation_Latitude, loc.getLatitude() + "");
        MMKV.defaultMMKV().putString(Constant.AMapLocation_Longitude, loc.getLongitude() + "");
        MMKV.defaultMMKV().putString(Constant.AMapLocation_CityCode, loc.getCityCode() + "");
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log_Ma.e(TAG, "LocalService:LocalService 启动");
        if (mediaPlayer != null) {
            mediaPlayer.stop();
            mediaPlayer.release();
            mediaPlayer = null;
        }
        mediaPlayer = MediaPlayer.create(this, R.raw.aa);
        mediaPlayer.setVolume(0f, 0f);//声音设置为0
        mediaPlayer.setLooping(true);  //循环播放
        mediaPlayer.start();
        //启用前台服务,提升优先级
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            startForeground(12001, NotifyManager.getInstance().getNotification(this, 1));
        }
        //绑定守护进程
        Intent intent3 = new Intent(this, RemoteService.class);
        bindService(intent3, connection, Context.BIND_ABOVE_CLIENT);
//        initTimer();
        handler.removeMessages(MSGWHAT);
        handler.sendEmptyMessageDelayed(MSGWHAT, 1000 * 2);
        return Service.START_STICKY;
    }

    private void initTimer() {
        destroyTimer();
        threadPool = Executors.newSingleThreadScheduledExecutor();
        threadPool.scheduleWithFixedDelay(new ScanScheduledExecutor(this), 5, 10, TimeUnit.SECONDS);
    }

    //静态弱引用方式,防止内存泄露
    private static class ScanScheduledExecutor implements Runnable {
        private SoftReference<Context> softReference;

        ScanScheduledExecutor(Context context) {
            softReference = new SoftReference<Context>(context);
        }

        @Override
        public void run() {
            try {
                Context context = softReference.get();
                if (context != null) {
                    boolean isScreenOn = PowerManagerUtil.getInstance().isScreenOn(context);
                    Log_Ma.e(TAG, "屏幕是否点亮:" + isScreenOn);
                    WeiLan_GaoDe.getInstance().initOneLocation(context, new WeiLan_GaoDe.OneListener() {
                        @Override
                        public void succeed(AMapLocation loc) {
                            Http_Tens.postService(loc, LocalService.class.getName());
                        }

                        @Override
                        public void onError() {
                            if (!isScreenOn) {
                                PowerManagerUtil.getInstance().awakening(App.getContext());
                            }
                        }
                    });
                }
            } catch (Exception e) {
                Log_Ma.e("ScheduledExecutorService e:" + e.toString());
            }
        }
    }

    private ServiceConnection connection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
            if (!Http_Date_Utils.getInstance().getUserID().equals("")) {
                try {
                    if (myBuilder != null) {
                        GuardAidl guardAidl = GuardAidl.Stub.asInterface(iBinder);
                        guardAidl.wakeUp();
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }

        @Override
        public void onServiceDisconnected(ComponentName componentName) {
            if (!Http_Date_Utils.getInstance().getUserID().equals("")) {
                String str = MMKV.defaultMMKV().getString(Constant.killService, "");
                if (!TextUtils.isEmpty(str)) {
                    Intent remoteService = new Intent(LocalService.this, RemoteService.class);
                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                        startForegroundService(remoteService);
                    } else {
                        startService(remoteService);
                    }
                    Intent intent = new Intent(LocalService.this, RemoteService.class);
                    bindService(intent, this, Context.BIND_ABOVE_CLIENT);
                }
            }
        }
    };

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log_Ma.e(TAG, "onDestroy() called");
        unbindService(connection);
        destroyTimer();
        mClient.stopLocation();
        mClient.onDestroy();
        if (mediaPlayer != null) {
            mediaPlayer.stop();
            mediaPlayer.release();
            mediaPlayer = null;
        }
        mScreenListener.stopScreenReceiverListener();
        handler.removeCallbacksAndMessages(null);
    }

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

    private class MyBuilder extends GuardAidl.Stub {

        @Override
        public void wakeUp() {

        }
    }

    //先取消上一个任务,防止重复的任务
    private void destroyTimer() {
        if (threadPool != null) {
            Log_Ma.e(TAG, "destroyTimer() called");
            threadPool.shutdownNow();
            threadPool = null;
        }
    }

    private ScreenReceiverUtil.SreenStateListener mScreenListenerer = new ScreenReceiverUtil.SreenStateListener() {
        @Override
        public void onSreenOn() {
            Log_Ma.e(TAG, "开屏 -------------------");
        }

        @Override
        public void onSreenOff() {
            Log_Ma.e(TAG, "锁屏 打开了1像素Activity");
            mScreenManager.startActivity();
        }

        @Override
        public void onUserPresent() {
            Log_Ma.e(TAG, "解锁 关闭了1像素Activity");
            mScreenManager.finishActivity();
        }
    };
}

 


守护进程:

/**
 * Author : 马占柱
 * E-mail : mazhanzhu_3351@163.com
 * Time   : 2021/6/5 20:35
 * Desc   : 守护进程
 */
public class RemoteService extends Service {
    public static final String TAG = "守护进程";
    private MyBuilder myBuilder;

    @Override
    public void onCreate() {
        super.onCreate();
        if (myBuilder == null) {
            myBuilder = new MyBuilder();
        }

    }

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

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log_Ma.e(TAG, "RemoteService 绑定LocalService");
        bindService(new Intent(this, LocalService.class), connection, Context.BIND_ABOVE_CLIENT);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            startForeground(12003, NotifyManager.getInstance().getNotification(this, 3));
        }
        return Service.START_STICKY;
    }

    private class MyBuilder extends GuardAidl.Stub {
        @Override
        public void wakeUp() throws RemoteException {

        }
    }

    private ServiceConnection connection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName componentName, IBinder iBinder) {

        }

        @Override
        public void onServiceDisconnected(ComponentName componentName) {
            if (!Http_Date_Utils.getInstance().getUserID().equals("")) {
                String str = MMKV.defaultMMKV().getString(Constant.killService, "");
                if (!TextUtils.isEmpty(str)) {
                    startService(new Intent(RemoteService.this, LocalService.class));
                    bindService(new Intent(RemoteService.this, LocalService.class), this, Context.BIND_ABOVE_CLIENT);
                    PowerManagerUtil.getInstance().wakeUpScreen(RemoteService.this);
                }
            }
        }
    };

    @Override
    public void onDestroy() {
        super.onDestroy();
        unbindService(connection);
    }
}

 


Job线程

/**
 * Author : 马占柱
 * E-mail : mazhanzhu_3351@163.com
 * Time   : 2021/07/12 14:39
 * Desc   : Job线程
 */
public class JobHandlerService extends JobService {
    public static final String TAG = "JobHandlerService";
    private JobScheduler jobScheduler = null;

    @Override
    public boolean onStartJob(JobParameters jobParameters) {
        //开启定时任务 定时轮寻 判断应用Service是否被杀死
        Log_Ma.e(TAG, "onStartJob() called with: jobParameters = [" + jobParameters + "]");
        boolean messageServiceAlive = ServiceUtils.serviceAlive(LocalService.class.getName());
        if (!messageServiceAlive) {
            startService(this);
        }
        return false;
    }

    @Override
    public boolean onStopJob(JobParameters jobParameters) {
        //如果被杀死则重启Service
        Log_Ma.e(TAG, "onStopJob() called with: jobParameters = [" + jobParameters + "]");
        boolean messageServiceAlive = ServiceUtils.serviceAlive(LocalService.class.getName());
        if (!messageServiceAlive) {
            startService(this);
        }
        return false;
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log_Ma.e(TAG, "onStartCommand() called with: intent = [" + intent + "], flags = [" + flags + "], startId = [" + startId + "]");
        int startId1 = startId;
        startService(this);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            jobScheduler = (JobScheduler) getSystemService(Context.JOB_SCHEDULER_SERVICE);
            JobInfo.Builder builder = new JobInfo.Builder(startId1++, new ComponentName(this, JobHandlerService.class));

            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {//7.0 以上的版本 , 设置延迟 5 秒执行
                builder.setMinimumLatency(1000 * 30); //最短延迟时间,单位毫秒
                builder.setOverrideDeadline(1000 * 60); //最长延迟时间,单位毫秒
            } else {
                /*设置任务运行的周期(每X毫秒,运行一次)*/
                builder.setPeriodic(1000 * 60 * 1);
            }
            //共有(NETWORK_TYPE_NONE默认)、(NETWORK_TYPE_ANY任何网络状态)、(NETWORK_TYPE_UNMETERED不需要计量的网络状态)、(NETWORK_TYPE_NOT_ROAMING非漫游状态)
            builder.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY);

            /*是否需要在充电状态执行 默认是false,只有当设备在充电时这个任务才会被执行。
            这个也并非只是插入充电器,而且还要在电池处于健康状态的情况下才会触发,一般来说是手机电量>15%*/
            builder.setRequiresCharging(true);//是否需要在充电状态执行 默认是false

            /*指定Job在空闲状态才能运行。设备处于屏幕关闭或dreaming状态(类似window的休眠动画状态)71分钟后,执行工作*/
            builder.setRequiresDeviceIdle(false);

            /*这个方法告诉系统当设备重启之后任务是否还要继续执行。*/
            builder.setPersisted(false);

            /*
特殊:设置回退/重试的策略,详细的可以参阅Google API。
类似网络原理中的冲突退避,当一个任务的调度失败时需要重试,所采取的策略。
第一个参数时第一次尝试重试的等待间隔,单位为毫秒,
预设的参数有:DEFAULT_INITIAL_BACKOFF_MILLIS 30000 、MAX_BACKOFF_DELAY_MILLIS 18000000。
第二个参数是对应的退避策略,预设的参数有:BACKOFF_POLICY_EXPONENTIAL 二进制退避。
等待间隔呈指数增长 BACKOFF_POLICY_LINEAR。
*/
            builder.setBackoffCriteria(1000 * 60 * 1, JobInfo.BACKOFF_POLICY_LINEAR);//设置重试方案
            jobScheduler.schedule(builder.build());
        }
        return Service.START_STICKY;
    }

    private void startService(Context context) {
        String str = MMKV.defaultMMKV().getString(Constant.killService, "");
        if (!TextUtils.isEmpty(str)) {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                startForeground(12001, NotifyManager.getInstance().getNotification(this, 4));
            }
            startService(new Intent(context, LocalService.class));
            startService(new Intent(context, RemoteService.class));
        }
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log_Ma.e(TAG, "onDestroy() called");
    }

    @Override
    public void onCreate() {
        super.onCreate();
        Log_Ma.e(TAG, "onCreate() called");
    }
}
/**
 * Author : 马占柱
 * E-mail : mazhanzhu_3351@163.com
 * Time   : 2021/07/12 14:41
 * Desc   : 通知
 */
public class HideForegroundService extends Service {
    private Handler handler = null;

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

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        startForeground(12005, NotifyManager.getInstance().getNotification(this,5));
        if (handler == null) {
            handler = new Handler();
        }
        handler.postDelayed(new Runnable() {
            @Override
            public void run() {
                stopForeground(true);
                stopSelf();
            }
        }, 1500);
        return Service.START_NOT_STICKY;
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
    }
}

电池工具类 【保证在息屏状体下,CPU可以正常运行】
/**
 * Author : 马占柱
 * E-mail : mazhanzhu_3351@163.com
 * Time   : 2021/9/22 15:46
 * Desc   : 电池工具类 【保证在息屏状体下,CPU可以正常运行】
 */
public class PowerManagerUtil {
    public static final String TAG = "PowerManagerUtil";

    //使用volatile关键字保其可见性
    volatile private static PowerManagerUtil instance = null;
    private PowerManager.WakeLock mWakelock;

    private PowerManagerUtil() {
    }

    public static PowerManagerUtil getInstance() {
        try {
            if (instance != null) {//懒汉式

            } else {
                //创建实例之前可能会有一些准备性的耗时工作
                Thread.sleep(300);
                synchronized (PowerManagerUtil.class) {
                    if (instance == null) {//二次检查
                        instance = new PowerManagerUtil();
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return instance;
    }

    /**
     * @param context
     * @return 判断屏幕是否处于点亮状态 true【亮屏】 false【息屏】
     */
    public boolean isScreenOn(final Context context) {
        try {
            Method isScreenMethod = PowerManager.class.getMethod("isScreenOn", new Class[]{});
            PowerManager pm = (PowerManager) context.getSystemService(POWER_SERVICE);
            boolean screenState = (Boolean) isScreenMethod.invoke(pm);
            return screenState;
        } catch (Exception e) {
            return false;
        }
    }

    /**
     * 唤醒屏幕
     */
    @SuppressLint("InvalidWakeLockTag")
    public void wakeUpScreen(final Context context) {
        try {
            if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
                PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
                /*
                 * SCREEN_DIM_WAKE_LOCK     CPU:保持运转 屏幕:保持显示但可以是暗的 键盘灯:关闭
                 * SCREEN_BRIGHT_WAKE_LOCK  CPU:保持运转 屏幕:保持高亮 键盘灯:关闭
                 * FULL_WAKE_LOCK           CPU:保持运转 屏幕:保持高亮 键盘灯:点亮
                 * PARTIAL_WAKE_LOCK        CPU:保持运转 屏幕:可以关闭 键盘灯:可以关闭
                 *
                 * ACQUIRE_CAUSES_WAKEUP    强制使屏幕亮起,这种锁主要针对一些必须通知用户的操作【慎用,会导致锁屏情况下,来消息屏幕频繁亮起,体验不好!】
                 *                          不能和 PARTIAL_WAKE_LOCK 一起用
                 *
                 * ON_AFTER_RELEASE         在释放锁时回收activity的timer计时器【不能和 PARTIAL_WAKE_LOCK 一起用】
                 * */
                PowerManager.WakeLock lock = pm.newWakeLock(PowerManager.ACQUIRE_CAUSES_WAKEUP | PowerManager.SCREEN_DIM_WAKE_LOCK, TAG);
                /*
                 * https://blog.csdn.net/fengyeNom1/article/details/121373158【详解】
                 * 在通常的wakelock使用时,会报错:java.lang.RuntimeException: WakeLock under-locked。
                 * 这是因为出现了上述release函数末尾if(mCount<0)的情,用 setReferenceCounted(false) 就可以解决这个问题。
                 * 这个函数的作用:是不是需要计算锁的数量?设置为false时,在release的时候,不管你acquire()了多少回,可以一次releaseWakeLock掉。
                 *
                 * 注意这个方法默认为true,意味着一个WakeLock调用acquire()多次,也必须release()多次才能释放,
                 * 如果释放次数比acquire()多,则抛出异常: java.lang.RuntimeException: WakeLock under-locked
                 * */
                lock.setReferenceCounted(false);
                lock.acquire();
                lock.release();
                Log_Ma.e(TAG, "wakeUpScreen: 正常唤醒操作");
                // FIXME: 注意:WakeLock的设置是 Activiy 级别的,不是针对整个Application应用的。所以application下有多个activity一定需要注意下!
            }
        } catch (Exception e) {
            LiteOrmDBUtil.insert(new Bean_ERROR(0, "PowerManagerUtil类中wakeUpScreen方法手动获取异常:" + e.toString()));
            Log_Ma.e(TAG, "wakeUpScreen: " + e.toString());
        }
    }

    /**
     * 唤醒CPU
     */
    @SuppressLint("InvalidWakeLockTag")
    public void awakening(Context context) {
        try {
            if (mWakelock == null) {
                if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
                    PowerManager pm = (PowerManager) context.getSystemService(POWER_SERVICE);
                    mWakelock = pm.newWakeLock(PowerManager.ACQUIRE_CAUSES_WAKEUP | PowerManager.SCREEN_DIM_WAKE_LOCK, TAG);
                    mWakelock.setReferenceCounted(false);
                    mWakelock.acquire();//点亮屏幕
                }
            }
            Log_Ma.e(TAG, "awakening: 获取CPU唤醒锁-------获取----获取---");
        } catch (Exception e) {
            Log_Ma.e(TAG, "awakening: 获取CPU唤醒锁" + e.toString());
        }
    }

    public void release() {
        try {
            if (mWakelock != null) {
                mWakelock.release();
                mWakelock = null;
            }
            Log_Ma.e(TAG, "awakening: 释放CPU唤醒锁---------- 释放---- 释放 释放--");
        } catch (Exception e) {
            Log_Ma.e(TAG, "awakening: 释放CPU唤醒锁" + e.toString());
        }
    }
}

【总开关设置,开启服务VS关闭服务】
/**
 * Author : 马占柱
 * E-mail : mazhanzhu_3351@163.com
 * Time   : 2021/6/5 17:42
 * Desc   : 保活设置
 */
public class KeepLive {
    public static final String TAG = "KeepLive";

    public static void startWork(Context context) {
        MMKV.defaultMMKV().putString(Constant.killService, "mzz");//一定要注意这个标签的使用,就是本地持久化一个数值,后边要判断的

        //-----------------------------------切换双进程保活------------------------------------------
        MMKV.defaultMMKV().putString(Constant.Service_TAG, "1");
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            //启动定时器,在定时器中启动本地服务和守护进程
            Intent jobSer = new Intent(context, JobHandlerService.class);
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                context.startForegroundService(jobSer);
            } else {
                context.startService(jobSer);
            }
        } else {
            //启动本地服务
            Intent localIntent = new Intent(context, LocalService.class);
            //启动守护进程
            Intent guardIntent = new Intent(context, RemoteService.class);
            context.startService(localIntent);
            context.startService(guardIntent);
        }
    }

    public static void stop(Context context) {
        MMKV.defaultMMKV().removeValueForKey(Constant.killService);

        Intent localIntent = new Intent(context, LocalService.class);
        Intent guardIntent = new Intent(context, RemoteService.class);
        Intent hideIntent = new Intent(context, HideForegroundService.class);
        Intent jobIntent = new Intent(context, JobHandlerService.class);
        context.stopService(jobIntent);
        context.stopService(hideIntent);
        context.stopService(localIntent);
        context.stopService(guardIntent);
    }
}

“1”像素Activity
/**
 * Author : 马占柱
 * E-mail : mazhanzhu_3351@163.com
 * Time   : 2021/5/23 9:48
 * Desc   : “1”像素Activity
 */
public class KeepLiveActivity extends AppCompatActivity {
    public static final String TAG = "KeepLiveActivity";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Window mWindow = getWindow();
        mWindow.setGravity(Gravity.LEFT | Gravity.TOP);
        WindowManager.LayoutParams attrParams = mWindow.getAttributes();
        attrParams.x = 0;
        attrParams.y = 0;
        attrParams.height = 1;
        attrParams.width = 1;
        mWindow.setAttributes(attrParams);
        ScreenManager.getInstance(this).setSingleActivity(this);
        startSer();
        Log_Ma.e(TAG, "嘿嘿~,用到我,起来了");
    }

    @Override
    protected void onDestroy() {
        startSer();
        super.onDestroy();
        Log_Ma.e(TAG, "嘿嘿~,不用我,关闭了");
    }

    private void startSer() {
        if (!ServiceUtils.serviceAlive(LocalService_NoKip.class.getName())) {
            Intent intentAlive = new Intent(this, LocalService_NoKip.class);
            startService(intentAlive);
        }
    }
}

 别忘了在manifest里面配置

<activity
            android:name=".kepplive.KeepLiveActivity"
            android:configChanges="keyboardHidden|orientation|screenSize|navigation|keyboard"
            android:excludeFromRecents="true"
            android:finishOnTaskLaunch="false"
            android:launchMode="singleInstance"
            android:theme="@style/SingleActivityStyle" />

用到的主题theme

    <style name="SingleActivityStyle">
        <item name="android:windowBackground">@android:color/transparent</item>
        <item name="android:windowFrame">@null</item>
        <item name="android:windowNoTitle">true</item>
        <item name="windowActionBar">false</item>
        <item name="windowNoTitle">true</item>
        <item name="android:windowIsFloating">true</item>
        <item name="android:windowContentOverlay">@null</item>
        <item name="android:backgroundDimEnabled">false</item>
        <item name="android:windowAnimationStyle">@null</item>
        <item name="android:keepScreenOn">true</item>
        <item name="android:windowDisablePreview">true</item>
        <item name="android:windowNoDisplay">false</item>
    </style>
对1像素Activity进行防止内存泄露的处理,新建一个ScreenManager类
/**
 * Author : 马占柱
 * E-mail : mazhanzhu_3351@163.com
 * Time   : 2021/9/22 9:41
 * Desc   : 对1像素Activity进行防止内存泄露的处理,新建一个ScreenManager类
 */
public class ScreenManager {
    public static final String TAG="ScreenManager";
    private static ScreenManager sInstance;
    private Context mContext;
    private WeakReference<Activity> mActivity;

    private ScreenManager(Context mContext) {
        this.mContext = mContext;
    }

    public static ScreenManager getInstance(Context context) {
        if (sInstance == null) {
            sInstance = new ScreenManager(context);
        }
        return sInstance;
    }

    /**
     * 获得 KeepLiveActivity 的引用
     */
    public void setSingleActivity(Activity activity) {
        mActivity = new WeakReference<>(activity);
    }

    /**
     * 启动 KeepLiveActivity
     */
    public void startActivity() {
        Intent intent = new Intent(mContext, KeepLiveActivity.class);
        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        mContext.startActivity(intent);
    }

    /**
     * 结束SinglePixelActivity
     */
    public void finishActivity() {
        if (mActivity != null) {
            Activity activity = mActivity.get();
            if (activity != null) {
                activity.finish();
            }
        }
    }
}

 锁屏解锁的广播动态注册监听

/**
 * Author : 马占柱
 * E-mail : mazhanzhu_3351@163.com
 * Time   : 2021/9/22 9:40
 * Desc   : 锁屏解锁的广播动态注册监听
 */
public class ScreenReceiverUtil {
    private Context mContext;
    private SreenBroadcastReceiver mScreenReceiver;
    private SreenStateListener mStateReceiverListener;

    public ScreenReceiverUtil(Context mContext) {
        this.mContext = mContext;
    }

    public void setScreenReceiverListener(SreenStateListener mStateReceiverListener) {
        this.mStateReceiverListener = mStateReceiverListener;
        // 动态启动广播接收器
        this.mScreenReceiver = new SreenBroadcastReceiver();
        IntentFilter filter = new IntentFilter();
        filter.addAction(Intent.ACTION_SCREEN_ON);
        filter.addAction(Intent.ACTION_SCREEN_OFF);
        filter.addAction(Intent.ACTION_USER_PRESENT);
        mContext.registerReceiver(mScreenReceiver, filter);
    }

    public void stopScreenReceiverListener() {
        mContext.unregisterReceiver(mScreenReceiver);
    }

    /**
     * 监听sreen状态对外回调接口
     */
    public interface SreenStateListener {
        void onSreenOn();

        void onSreenOff();

        void onUserPresent();
    }

    public class SreenBroadcastReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
            if (mStateReceiverListener == null) {
                return;
            }
            if (Intent.ACTION_SCREEN_ON.equals(action)) { // 开屏
                mStateReceiverListener.onSreenOn();
            } else if (Intent.ACTION_SCREEN_OFF.equals(action)) { // 锁屏
                mStateReceiverListener.onSreenOff();
            } else if (Intent.ACTION_USER_PRESENT.equals(action)) { // 解锁
                mStateReceiverListener.onUserPresent();
            }
        }
    }
}

 一像素的知识完事了,然后去 AIDL


 AIDL

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

interface GuardAidl {
     //相互唤醒服务
         void wakeUp();
}

 manifest文件配置

        <service android:name=".kepplive.LocalService" />
        <service
            android:name=".kepplive.RemoteService"
            android:process=":remote">

        </service>
        <service
            android:name=".kepplive.JobHandlerService"
            android:permission="android.permission.BIND_JOB_SERVICE" />
        <service android:name=".kepplive.HideForegroundService" />

开始使用

 在需要开启的地方调用:KeepLive.startWork(context);

结束定位调用:KeepLive.stop(context);


 最后我这里有一个手机电池优化的方法,就是app在锁屏状态下,不因为电池优化策略而被杀死

//优化电池
public void setPower(Context context) {
        boolean isIgnoring = false;
        PowerManager powerManager = (PowerManager) context.getSystemService(POWER_SERVICE);
        if (powerManager != null) {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                isIgnoring = powerManager.isIgnoringBatteryOptimizations(context.getPackageName());//是否进行了电池优化处理
            }
        }
        if (!isIgnoring) {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                try {
                    Intent intent = new Intent(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS);
                    intent.setData(Uri.parse("package:" + context.getPackageName()));
                    context.startActivity(intent);
                } catch (Exception e) {

                }
            }
        }
    }

最后我又实现了一个逻辑,就是在15S杀死得情况下,不调用进程保活,要是超出15S的话,才调佣保活机制,这样的话,体验更好点,不至于说关不掉,呵呵哈哈哈或

在Application中的onCreate()里面调佣getAPPTime();

private void getAPPTime() {
        registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() {

            @Override
            public void onActivityCreated(@NonNull Activity activity, @Nullable Bundle savedInstanceState) {
                Log_Ma.e(TAG, "onActivityCreated: " + getAcName(activity));
            }

            @Override
            public void onActivityStopped(@NonNull Activity activity) {
                Log_Ma.e(TAG, "onActivityStopped: " + getAcName(activity));
                count--;
                if (count == 0) {
                    mTime = System.currentTimeMillis();
                    Log_Ma.e(TAG, ">>>>>>>>>>>>>>>>>>>切到后台");
                }
            }

            @Override
            public void onActivityStarted(@NonNull Activity activity) {
                Log_Ma.e(TAG, "onActivityStarted: " + getAcName(activity));
                if (count == 0) {
                    Log_Ma.e(TAG, ">>>>>>>>>>>>>>>>>>>切到前台");
                }
                count++;
            }

            @Override
            public void onActivityResumed(@NonNull Activity activity) {
//                Log_Ma.e(TAG, "onActivityResumed: " + getName(activity));
            }

            @Override
            public void onActivityPaused(@NonNull Activity activity) {
//                Log_Ma.e(TAG, "onActivityPaused: " + getName(activity));
            }


            @Override
            public void onActivitySaveInstanceState(@NonNull Activity activity, @NonNull Bundle outState) {
//                Log_Ma.e(TAG, "onActivitySaveInstanceState: " + getName(activity));
            }

            @Override
            public void onActivityDestroyed(@NonNull Activity activity) {
                Log_Ma.e(TAG, "onActivityDestroyed: " + getAcName(activity));
                if (count == 0) {
                    String name = activity.getClass().getSimpleName();
                    if (TextUtils.equals(name, Activity_Main_2.class.getSimpleName())) {
                        if (System.currentTimeMillis() - mTime < 1000 * 15) {
                            KeepLive.stop(activity);
                        }
                    }
                }
            }

            private String getAcName(Activity activity) {
                return activity.getPackageName() + " / " + activity.getClass().getSimpleName();
            }
        });
    }

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 14
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 14
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值