打盹模式停止了定位服务
Posted
技术标签:
【中文标题】打盹模式停止了定位服务【英文标题】:Location service got stopped by Doze mode 【发布时间】:2017-05-03 22:39:27 【问题描述】:我正在开发运动跟踪应用程序,它使用位置管理器和 gps 提供程序来每秒获取位置更新,即使屏幕关闭并且手机在口袋里。
当用户在我的活动中按下开始按钮时,我会在前台启动服务,显示通知并注册位置监听器。
服务开始接收位置更新并将它们写入我的跟踪文件。
我突然收到日志消息“电源管理器空闲模式:真”,手机进入打盹模式,我的服务停止获取任何位置更新,直到手机唤醒。
我阅读了有关 Doze mode 的文档,发现它不应该影响定位服务,但在我的情况下确实如此。
可能是我做错了什么。这是我的服务代码,非常感谢任何帮助。
public class LocService
extends Service
implements LocationListener, GpsStatus.Listener
private String mName;
private volatile Looper mServiceLooper;
private volatile ServiceHandler mServiceHandler;
private LocationManager locationManager;
public LocService(String name)
super();
mName = name;
private final class ServiceHandler extends Handler
public ServiceHandler(Looper looper)
super(looper);
@Override
public void handleMessage(Message msg)
if (msg != null && msg.obj != null)
onHandleIntent((Intent)msg.obj);
else
logMessage("msg for intent is not good");
@Override
public void onCreate()
super.onCreate();
HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
thread.start();
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
logMessage("Enabling Doze mode listener");
IntentFilter filter = new IntentFilter();
filter.addAction(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED);
registerReceiver(new BroadcastReceiver()
@Override
public void onReceive(Context context, Intent intent)
onDeviceIdleChanged();
, filter);
locationManager = (LocationManager) getSystemService(LOCATION_SERVICE);
@TargetApi(Build.VERSION_CODES.M)
private void onDeviceIdleChanged()
PowerManager powerManager = (PowerManager) getSystemService(POWER_SERVICE);
if(powerManager != null)
logMessage("Power manager idle mode: " + powerManager.isDeviceIdleMode());
else
logMessage("Power manager idle changed to ?");
protected void onHandleIntent(Intent intent)
//call start/stop location logging on proper intent
if(intent.getIntExtra("cmd", -1) == 1)
startLogging();
else
stopLogging();
private void startLogging()
logMessage("LocationService.startLogging");
try
locationManager.addGpsStatusListener(this);
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 500, 0, this);
logMessage("requesting gps updates");
startForeground(ONGOING_NOTIFICATION, getNotification(-1, -1, true, false));
logMessage("Sending foreground service notification");
catch (SecurityException ex)
logMessage(" SecurityException while requesting location info: " + ex);
private void stopLogging()
try
locationManager.removeUpdates(this);
stopForeground(true);
notificationManager.cancel(ONGOING_NOTIFICATION);
catch (SecurityException ex)
logMessage(" SecurityException on stopLogging with location manager: " + ex);
@Override
public void onLocationChanged(Location location)
//save location lat, lon directly to track file
//flush file
@Override
public void onStatusChanged(String provider, int status, Bundle extras)
//do nothing
@Override
public void onProviderEnabled(String provider)
logMessage("Location provider enabled " + provider);
@Override
public void onProviderDisabled(String provider)
logMessage("Location provider disabled " + provider);
@Override
public void onGpsStatusChanged(int event)
try
logMessage(" *** onGpsStatusChanged with " + event);
GpsStatus status = locationManager.getGpsStatus(null);
int inFix = 0;
int total = 0;
for (GpsSatellite satellite : status.getSatellites())
if (satellite.usedInFix()) inFix++;
total++;
logMessage(" Sats: " + total + " in fix " + inFix);
catch (SecurityException sex)
catch (Exception ex)
@Override
public void onStart(Intent intent, int startId)
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
msg.obj = intent;
mServiceHandler.sendMessage(msg);
@Override
public int onStartCommand(Intent intent, int flags, int startId)
onStart(intent, startId);
return START_STICKY;
@Override
public void onDestroy()
mServiceLooper.quit();
try
locationManager.removeUpdates(this);
catch (SecurityException ex)
logMessage(" SecurityException on Destroy service with location manager: " + ex);
@Override
public IBinder onBind(Intent intent)
return null;
private void logMessage(String msg)
Log.i("LocServ", msg);
【问题讨论】:
为 M:code.google.com/p/android/issues/detail?id=193802 找到了这个 android 错误,可能这也是我的情况,但我不确定我在 android 7.1.1 上也有同样的行为。 【参考方案1】:当 ACTION_DEVICE_IDLE_MODE_CHANGED 被触发时,打瞌睡是打开还是关闭,这并不是给定的。影响空闲模式的因素还有很多。
尝试创建并获取 WakeLock。
PowerManager.WakeLock getLock(Context context, String lockName)
if (wakeLock == null)
PowerManager mgr = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
wakeLock = mgr.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, lockName);
return wakeLock;
//on start service
getLock(ctxt.getApplicationContext(), "lockName").acquire();
//on destroy service
@Override
public void onDestroy()
PowerManager.WakeLock lock = getLock(this.getApplicationContext(), "lockName");
if (lock.isHeld())
lock.release();
super.onDestroy();
【讨论】:
我安装了监听器,它会输出有关设备进入打盹模式的日志。同样在“打瞌睡限制”中说“系统忽略唤醒锁”。以上是关于打盹模式停止了定位服务的主要内容,如果未能解决你的问题,请参考以下文章