打盹模式停止了定位服务

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();
    

【讨论】:

我安装了监听器,它会输出有关设备进入打盹模式的日志。同样在“打瞌睡限制”中说“系统忽略唤醒锁”。

以上是关于打盹模式停止了定位服务的主要内容,如果未能解决你的问题,请参考以下文章

Android O 在打盹模式下前台服务未接收位置更新

打盹模式 - 前台服务是不是继续运行?

在打盹模式下在前台服务中重复任务

以打盹模式启动前台服务

打盹模式如何影响后台/前台服务,有/没有部分/全部唤醒锁?

如何在 Android 上测试打盹模式?