Android 设备在黑屏的分钟后可能会发生多种情况:

应用程序切后台后进程资源被系统回收,导致不能持续定位。

解决办法:

长连接定时唤醒cpu(解决黑屏定位、黑屏断网问题)

对于原生Android系统可采用google给出的提升后台应用进程优先级的解决方案来解决,可参考google Android 开发者官网。

对于国内厂商提供的Android系统需要联系到对应的厂商进行系统底层应用白名单授权,才可以保证App进程在后台处于活跃状态。

CPU会处于休眠状态(不同厂商生产的设备CPU休眠时间不尽相同)(包含AP[Application Processor,ARM架构的处理器,用于支撑Android系统运行]和BP[Baseband Processor,运行实时操作系统,通讯协议栈等])。一旦当CPU处于休眠状态,设备将无法正常链接网络,APP的定位请求也将无法正常发送。

解决办法:

通过创建Timer来保持CPU唤醒状态:

Android 的 Timer 类可以用来计划需要执行的任务。但 Timer 的问题是比较消耗手机电量(实现是用 WakeLock 让 CPU 保持唤醒状态);另外一点是:部分厂商将WakeLock也设置了休眠时间,就是说 Timer 很可能和CPU一起处于休眠状态。Timer 类只能解决一小部分问题。

通过AlarmManager保持CPU处于唤醒状态:

AlarmManager 是 Android 系统封装的用于管理 RTC 的模块,RTC (Real Time Clock) 是一个独立的硬件时钟,可以在 CPU 休眠时正常运行,在预设的时间到达时,通过中断唤醒 CPU。用 AlarmManager 来定时执行任务,CPU 可以正常的休眠,需要运行定位时醒来即可。但部分厂商为了使设备更加省电,将AlarmManager也做出了修改,例如5s一次的响应更改为50s或者是几分钟,有些干脆在CPU休眠后彻底停掉了。

通过心跳长链接保持client端CPU处于唤醒状态:(推荐)

最佳唤醒CPU的方法是通过server端与client端的长链接通信。例如每次长链接保持5分钟时间,每30s通信一次,这样可以有效确保CPU处于唤醒状态。

开启前台server(进程保活)

思路:模仿一个音乐类软件,开启一个前台server并循环播放无声音乐

package com.guoshikeji.xiaoxiangDriver.services;

import android.annotation.SuppressLint;

import android.app.Notification;

import android.app.NotificationChannel;

import android.app.NotificationManager;

import android.app.PendingIntent;

import android.app.Service;

import android.content.Context;

import android.content.Intent;

import android.media.MediaPlayer;

import android.os.IBinder;

import com.guoshikeji.xiaoxiangDriver.MainActivity;

import com.guoshikeji.xiaoxiangDriver.R;

import static android.app.Notification.PRIORITY_MAX;

/**

* Created by tyl

* 2019/11/12/012

* Describe:

*/

public class BackGroundService extends Service {

Notification notification;

private Context mContext;

private static Thread uploadGpsThread;

private MediaPlayer bgmediaPlayer;

private boolean isrun = true;

@Override

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

mContext = this;

Intent notificationIntent = new Intent(this, MainActivity.class);

PendingIntent pendingIntent = PendingIntent.getActivity(mContext, 0,

notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT);

//1.通知栏占用,不清楚的看官网或者音乐类APP的效果

notification = new Notification.Builder(mContext)

.setSmallIcon(R.mipmap.ic_launcher)

.setWhen(System.currentTimeMillis())

.setTicker(getResources().getString(R.string.app_name))

.setContentTitle(getResources().getString(R.string.app_name))

.setContentText("正在后台运行")

.setOngoing(true)

.setPriority(PRIORITY_MAX)

.setContentIntent(pendingIntent)

.setAutoCancel(false)

.build();

/*使用startForeground,如果id为0,那么notification将不会显示*/

startForeground(2479, buildNotification());

2.开启线程(或者需要定时操作的事情)

//if(uploadGpsThread == null){

//    uploadGpsThread = new Thread(new Runnable() {

//        @Override

//        public void run() {

//            //这里用死循环就是模拟一直执行的操作

//            while (isrun){

//

//                //你需要执行的任务

//                //doSomething();

//

//                try {

//                    Thread.sleep(10000L);

//                } catch (InterruptedException e) {

//                    e.printStackTrace();

//                }

//            }

//        }

//    });

//}

//3.最关键的神来之笔,也是最投机的动作,没办法要骗过CPU

//这就是播放音乐类APP不被杀的做法,自己找个无声MP3放进来循环播放

//slient自己百度找一个无声的mp3即可

if(bgmediaPlayer == null){

bgmediaPlayer = MediaPlayer.create(this,R.raw.slient);

bgmediaPlayer.setLooping(true);

bgmediaPlayer.start();

}

return START_STICKY;

}

@Override

public IBinder onBind(Intent intent) {

// TODO: Return the communication channel to the service.

throw new UnsupportedOperationException("Not yet implemented");

}

@Override

public void onDestroy() {

isrun = false;

stopForeground(true);

bgmediaPlayer.release();

stopSelf();

super.onDestroy();

}

private NotificationManager notificationManager;

private boolean isCreateChannel = false;

@SuppressLint("NewApi")

private Notification buildNotification() {

Notification.Builder builder = null;

Notification notification = null;

if (android.os.Build.VERSION.SDK_INT >= 26) {

if (null == notificationManager) {

notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);

}

String channelId = getPackageName();

if (!isCreateChannel) {

NotificationChannel notificationChannel = new NotificationChannel(channelId,

"BackgroundLocation", NotificationManager.IMPORTANCE_DEFAULT);

notificationChannel.enableLights(false);//是否在桌面icon右上角展示小圆点

notificationChannel.setShowBadge(true); //是否在久按桌面图标时显示此渠道的通知

notificationManager.createNotificationChannel(notificationChannel);

isCreateChannel = true;

}

builder = new Notification.Builder(getApplicationContext(), channelId);

} else {

builder = new Notification.Builder(getApplicationContext());

}

builder.setSmallIcon(R.mipmap.icon_notifacation_log)

.setColor(getResources().getColor(R.color.main_color))

.setContentTitle(getResources().getString(R.string.app_name))

.setContentText("正在后台运行")

.setWhen(System.currentTimeMillis());

if (android.os.Build.VERSION.SDK_INT >= 16) {

notification = builder.build();

} else {

return builder.getNotification();

}

return notification;

}

}

清单文件注册:

android:name=".services.BackGroundService"

android:enabled="true"

android:exported="true"/>

启动server:

Intent forgroundService = new Intent(this,BackGroundService.class);

startService(forgroundService);