####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并循环播放无声音乐
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 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; } }
清单文件注册:
1 2 3 4 <service android:name=".services.BackGroundService" android:enabled="true" android:exported="true"/>
启动server:
1 2 Intent forgroundService = new Intent(this,BackGroundService.class); startService(forgroundService);