4

Мы работаем над приложением для отслеживания мобильных устройств. Для обновлений местоположения API с плавающим местоположением используется с высокой степенью точности в качестве приоритета.Обновление фонового местоположения Android не происходит, когда экран выключен

Обновление местоположения требуется, даже если экран выключен. Итак, мы используем фон Service. Фон Service также приобретает частичный WakeLock, так что устройство не переходит в режим сна. На заднем плане Service мы запрашиваем обновления местоположения с ожидающим обновлением Service.

Проблема в том, что мы только получаем обновления местоположения, когда экран включен. Как только экран отключится, обновления обновлений прекратятся. Также есть Thread, управляемый Service, который не убивает ни в какой момент.

Создание запроса местоположения снова, когда экран выключен BroadcastReceiver, также не работает.

Вот класс фон Service (RouteExecution):

private static final String TAG = "RouteExecution"; 

private static RouteExecution routeExecution = null; 

private static GoogleApiClient mGoogleApiClient; 
private static PendingIntent pendingIntent = null; 
private PowerManager.WakeLock waitLock; 
/** 
* Creates an IntentService. Invoked by your subclass's constructor. 
*/ 
public RouteExecution() { 
    super(TAG); 

    RouteExecution.routeExecution = this; 
} 

@Override 
public void onCreate() { 
    super.onCreate(); 

    mGoogleApiClient = new GoogleApiClient.Builder(this) 
      .addApi(LocationServices.API) 
      .addConnectionCallbacks(this) 
      .addOnConnectionFailedListener(this) 
      .build(); 

    mGoogleApiClient.connect(); 

    IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_ON); 
    filter.addAction(Intent.ACTION_SCREEN_OFF); 
    BroadcastReceiver mReceiver = new PowerButtonReceiver(); 
    registerReceiver(mReceiver, filter); 

    PowerManager powerManager = (PowerManager) getSystemService(Context.POWER_SERVICE); 
    waitLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG); 
    waitLock.acquire(); 
} 

@Override 
protected void onHandleIntent(Intent intent) { 

    if (LocationResult.hasResult(intent)) { 

     LocationResult locationResult = LocationResult.extractResult(intent); 
     Location location = locationResult.getLastLocation(); 

     GPSLocation gpsLocation = new GPSLocation(location); 

     Log.d(TAG, "Location Accuracy: " + location.getAccuracy() + " " 
       + " has: " + location.hasAccuracy() + " Provider: " + location.getProvider() 
       + " long: " + location.getLongitude() + " lat: " + location.getLatitude()); 
    } 
} 



public boolean checkLocationPermission() { 

    if (ActivityCompat.checkSelfPermission(routeExecution, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED 
      && ActivityCompat.checkSelfPermission(routeExecution, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) { 
     // ActivityCompat#requestPermissions 
     // here to request the missing permissions, and then overriding 
     // public void onRequestPermissionsResult(int requestCode, String[] permissions, 
     //           int[] grantResults) 
     // to handle the case where the user grants the permission. See the documentation 
     // for ActivityCompat#requestPermissions for more details. 
     return false; 
    } 

    return true; 
} 

public void createLocationListener() { 

    if (!this.checkLocationPermission()) { 
     return; 
    } 

    LocationRequest mLocationRequest = LocationRequest.create(); 
    mLocationRequest.setInterval(5000); 
    mLocationRequest.setFastestInterval(5000); 
    mLocationRequest.setSmallestDisplacement(0); 
    mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY); 

    PendingResult<Status> statusPendingResult = LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, 
      mLocationRequest, pendingIntent); 
} 

@Override 
public void onConnected(@Nullable Bundle bundle) { 

    Log.d(TAG, mGoogleApiClient.isConnected() + " On Connected"); 
    synchronized (this) { 

      createLocationListener(); 
    } 
} 


public static GoogleApiClient getmGoogleApiClient() { 
    return mGoogleApiClient; 
} 

@Override 
public void onDestroy() { 
    super.onDestroy(); 


    waitLock.release(); 
    mGoogleApiClient.disconnect(); 
} 

public static RouteExecution getRouteExecution() { 
    return routeExecution; 
} 

public static void setPendingIntent(PendingIntent pendingIntent) { 
    RouteExecution.pendingIntent = pendingIntent; 
} 

Service запускается с помощью AlarmManager. Вот добыча:

AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); 
Intent updateServiceIntent = new Intent(context, RouteExecution.class); 
PendingIntent pendingUpdateIntent = PendingIntent.getService(context, 0, updateServiceIntent, 0); 
RouteExecution.setPendingIntent(pendingUpdateIntent); 
alarmManager.set(AlarmManager.RTC_WAKEUP, 50000, pendingUpdateIntent); 

BroadcastReceiver:

public class PowerButtonReceiver extends BroadcastReceiver { 
    private static final String TAG = "PowerButton"; 

    @Override 
    public void onReceive(Context context, Intent intent) { 

     Log.d(TAG, "Power Button"); 
     if (RouteExecution.getRouteExecution() != null) { 
      RouteExecution.getRouteExecution().createLocationListener(); 
     } 
    } 
} 

Как продолжать получать обновления местоположения, даже когда экран выключен.

Спасибо за помощь.

+1

Как вы начинаете свою «службу»? Покажите код как «Сервис», так и «BroadcastReceiver». – earthw0rmjim

+0

Проверьте этот вопрос, а также http: // stackoverflow.ком/вопросы/17613888/locationclient-оленья кожа-дать обратный вызов, когда экран-свет идет-офф-но-мой-wakefulth – abbath

ответ

0

Прежде всего, приобретение a WakeLock in Service не является надежным. Устройство может вернуться в режим сна до того, как этот код будет выполнен.

Я бы назвал PendingIntent.getBroadcast() вместо PendingIntent.getService(), потому что WakeLock технически гарантировано в течение onReceive() и начать Service оттуда.

Либо aquire WakeLock в onReceive(), начните Service и освободить WakeLock от Service, когда это уместно

или

использование WakefulBroadcastReceiver, который в основном делает то же самое, без необходимости реализовывать большинство этой логики сам.

Другой возможной проблемой является использование AlarmManager.set() на устройствах Marshmallow.

Сигнализации, установленные этим методом, не будут срабатывать на этих устройствах, если активен Doze.

Используйте setAndAllowWhileIdle() вместо set() на уровне API 23+.