画面がオフで電話がポケットに入っている場合でも、ロケーションマネージャーと gps プロバイダーを使用して毎秒ロケーションの更新を取得するスポーツ追跡アプリを開発しています。
ユーザーがアクティビティで開始ボタンを押すと、フォアグラウンドでサービスが開始され、通知が表示され、ロケーション リスナーが登録されます。
サービスが位置情報更新の受信を開始し、それらをトラック ファイルに書き込みます。
突然、「Power manager idle mode: true」というログ メッセージが表示され、電話が Doze モードになり、電話が復帰するまでサービスが位置情報の更新を停止します。
Doze モードに関するドキュメントを読んだところ、位置情報サービスに影響を与えるべきではないことがわかりましたが、私の場合はそうです。
私は何か間違ったことをしているのかもしれません。これが私のサービスのコードです。どんな助けも本当に感謝しています。
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);
}
}