Je dois surveiller les emplacements des utilisateurs à l'aide d'un service en arrière-plan, puis les charger et afficher le chemin d'accès à l'utilisateur.
En utilisant une activité, il était assez facile d’obtenir les positions GPS, mais quand je l’ai fait par le biais d’un service, j’ai eu un problème car il semble ne fonctionner que pour les threads en boucle (ou quelque chose comme ça).
En cherchant une solution sur Internet, j'ai découvert que beaucoup de gens avaient le même problème, mais que je ne trouvais pas de solution satisfaisante. Certaines personnes disent que vous devez utiliser prepare-> loop-> quit et d'autres que vous devez utiliser un handlerThread, mais je ne parviens toujours pas à trouver comment faire de telles choses de manière appropriée.
Je ne comprends pas quel est le problème avec la mise en œuvre de la fonctionnalité d'écoute de localisation dans le service. Cela ressemble assez à ce que vous faites dans Activity . Il vous suffit de définir un écouteur de localisation et de vous inscrire pour les mises à jour de localisation . Vous pouvez vous référer au code suivant comme exemple:
Fichier manifeste:
<uses-permission Android:name="Android.permission.ACCESS_FINE_LOCATION" />
<uses-permission Android:name="Android.permission.ACCESS_COARSE_LOCATION" />
<application
Android:icon="@drawable/ic_launcher"
Android:label="@string/app_name" >
<activity Android:label="@string/app_name" Android:name=".LocationCheckerActivity" >
<intent-filter >
<action Android:name="Android.intent.action.MAIN" />
<category Android:name="Android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service Android:name=".MyService" Android:process=":my_service" />
</application>
Le fichier de service:
import Android.app.Service;
import Android.content.Context;
import Android.content.Intent;
import Android.location.Location;
import Android.location.LocationManager;
import Android.os.Bundle;
import Android.os.IBinder;
import Android.util.Log;
public class MyService extends Service {
private static final String TAG = "BOOMBOOMTESTGPS";
private LocationManager mLocationManager = null;
private static final int LOCATION_INTERVAL = 1000;
private static final float LOCATION_DISTANCE = 10f;
private class LocationListener implements Android.location.LocationListener {
Location mLastLocation;
public LocationListener(String provider) {
Log.e(TAG, "LocationListener " + provider);
mLastLocation = new Location(provider);
}
@Override
public void onLocationChanged(Location location) {
Log.e(TAG, "onLocationChanged: " + location);
mLastLocation.set(location);
}
@Override
public void onProviderDisabled(String provider) {
Log.e(TAG, "onProviderDisabled: " + provider);
}
@Override
public void onProviderEnabled(String provider) {
Log.e(TAG, "onProviderEnabled: " + provider);
}
@Override
public void onStatusChanged(String provider, int status, Bundle extras) {
Log.e(TAG, "onStatusChanged: " + provider);
}
}
LocationListener[] mLocationListeners = new LocationListener[]{
new LocationListener(LocationManager.GPS_PROVIDER),
new LocationListener(LocationManager.NETWORK_PROVIDER)
};
@Override
public IBinder onBind(Intent arg0) {
return null;
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.e(TAG, "onStartCommand");
super.onStartCommand(intent, flags, startId);
return START_STICKY;
}
@Override
public void onCreate() {
Log.e(TAG, "onCreate");
initializeLocationManager();
try {
mLocationManager.requestLocationUpdates(
LocationManager.NETWORK_PROVIDER, LOCATION_INTERVAL, LOCATION_DISTANCE,
mLocationListeners[1]);
} catch (Java.lang.SecurityException ex) {
Log.i(TAG, "fail to request location update, ignore", ex);
} catch (IllegalArgumentException ex) {
Log.d(TAG, "network provider does not exist, " + ex.getMessage());
}
try {
mLocationManager.requestLocationUpdates(
LocationManager.GPS_PROVIDER, LOCATION_INTERVAL, LOCATION_DISTANCE,
mLocationListeners[0]);
} catch (Java.lang.SecurityException ex) {
Log.i(TAG, "fail to request location update, ignore", ex);
} catch (IllegalArgumentException ex) {
Log.d(TAG, "gps provider does not exist " + ex.getMessage());
}
}
@Override
public void onDestroy() {
Log.e(TAG, "onDestroy");
super.onDestroy();
if (mLocationManager != null) {
for (int i = 0; i < mLocationListeners.length; i++) {
try {
mLocationManager.removeUpdates(mLocationListeners[i]);
} catch (Exception ex) {
Log.i(TAG, "fail to remove location listners, ignore", ex);
}
}
}
}
private void initializeLocationManager() {
Log.e(TAG, "initializeLocationManager");
if (mLocationManager == null) {
mLocationManager = (LocationManager) getApplicationContext().getSystemService(Context.LOCATION_SERVICE);
}
}
}
public class GPSService extends Service implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener, com.google.Android.gms.location.LocationListener {
private LocationRequest mLocationRequest;
private GoogleApiClient mGoogleApiClient;
private static final String LOGSERVICE = "#######";
@Override
public void onCreate() {
super.onCreate();
buildGoogleApiClient();
Log.i(LOGSERVICE, "onCreate");
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.i(LOGSERVICE, "onStartCommand");
if (!mGoogleApiClient.isConnected())
mGoogleApiClient.connect();
return START_STICKY;
}
@Override
public void onConnected(Bundle bundle) {
Log.i(LOGSERVICE, "onConnected" + bundle);
Location l = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
if (l != null) {
Log.i(LOGSERVICE, "lat " + l.getLatitude());
Log.i(LOGSERVICE, "lng " + l.getLongitude());
}
startLocationUpdate();
}
@Override
public void onConnectionSuspended(int i) {
Log.i(LOGSERVICE, "onConnectionSuspended " + i);
}
@Override
public void onLocationChanged(Location location) {
Log.i(LOGSERVICE, "lat " + location.getLatitude());
Log.i(LOGSERVICE, "lng " + location.getLongitude());
LatLng mLocation = (new LatLng(location.getLatitude(), location.getLongitude()));
EventBus.getDefault().post(mLocation);
}
@Override
public void onDestroy() {
super.onDestroy();
Log.i(LOGSERVICE, "onDestroy - Estou sendo destruido ");
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onConnectionFailed(ConnectionResult connectionResult) {
Log.i(LOGSERVICE, "onConnectionFailed ");
}
private void initLocationRequest() {
mLocationRequest = new LocationRequest();
mLocationRequest.setInterval(5000);
mLocationRequest.setFastestInterval(2000);
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
}
private void startLocationUpdate() {
initLocationRequest();
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
// TODO: Consider calling
// 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;
}
LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, this);
}
private void stopLocationUpdate() {
LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, this);
}
protected synchronized void buildGoogleApiClient() {
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addOnConnectionFailedListener(this)
.addConnectionCallbacks(this)
.addApi(LocationServices.API)
.build();
}
}
En complément, j'ai implémenté cette méthode et ai généralement travaillé dans ma classe de service
À mon service
@Override
public void onCreate()
{
mHandler = new Handler(Looper.getMainLooper());
mHandler.post(this);
super.onCreate();
}
@Override
public void onDestroy()
{
mHandler.removeCallbacks(this);
super.onDestroy();
}
@Override
public void run()
{
InciarGPSTracker();
}
Voici ma solution
Etape 1 Enregistrer le serice dans le manifeste
<receiver
Android:name=".MySMSBroadcastReceiver"
Android:exported="true">
<intent-filter>
<action Android:name="com.google.Android.gms.auth.api.phone.SMS_RETRIEVED" />
</intent-filter>
</receiver>
Step2 Code de service
public class FusedLocationService extends Service {
private String mLastUpdateTime = null;
// bunch of location related apis
private FusedLocationProviderClient mFusedLocationClient;
private SettingsClient mSettingsClient;
private LocationRequest mLocationRequest;
private LocationSettingsRequest mLocationSettingsRequest;
private LocationCallback mLocationCallback;
private Location lastLocation;
// location updates interval - 10sec
private static final long UPDATE_INTERVAL_IN_MILLISECONDS = 5000;
// fastest updates interval - 5 sec
// location updates will be received if another app is requesting the locations
// than your app can handle
private static final long FASTEST_UPDATE_INTERVAL_IN_MILLISECONDS = 500;
private DatabaseReference locationRef;
private int notificationBuilder = 0;
private boolean isInitRef;
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.log("LOCATION GET DURATION", "start in service");
init();
return START_STICKY;
}
/**
* Initilize Location Apis
* Create Builder if Share location true
*/
private void init() {
mFusedLocationClient = LocationServices.getFusedLocationProviderClient(this);
mSettingsClient = LocationServices.getSettingsClient(this);
mLocationCallback = new LocationCallback() {
@Override
public void onLocationResult(LocationResult locationResult) {
super.onLocationResult(locationResult);
receiveLocation(locationResult);
}
};
mLocationRequest = new LocationRequest();
mLocationRequest.setInterval(UPDATE_INTERVAL_IN_MILLISECONDS);
mLocationRequest.setFastestInterval(FASTEST_UPDATE_INTERVAL_IN_MILLISECONDS);
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder();
builder.addLocationRequest(mLocationRequest);
mLocationSettingsRequest = builder.build();
startLocationUpdates();
}
/**
* Request Location Update
*/
@SuppressLint("MissingPermission")
private void startLocationUpdates() {
mSettingsClient
.checkLocationSettings(mLocationSettingsRequest)
.addOnSuccessListener(locationSettingsResponse -> {
Log.log(TAG, "All location settings are satisfied. No MissingPermission");
//noinspection MissingPermission
mFusedLocationClient.requestLocationUpdates(mLocationRequest, mLocationCallback, Looper.myLooper());
})
.addOnFailureListener(e -> {
int statusCode = ((ApiException) e).getStatusCode();
switch (statusCode) {
case LocationSettingsStatusCodes.RESOLUTION_REQUIRED:
Log.loge("Location settings are not satisfied. Attempting to upgrade " + "location settings ");
break;
case LocationSettingsStatusCodes.SETTINGS_CHANGE_UNAVAILABLE:
Log.loge("Location settings are inadequate, and cannot be " + "fixed here. Fix in Settings.");
}
});
}
/**
* onLocationResult
* on Receive Location share to other activity and save if save true
*
* @param locationResult
*/
private void receiveLocation(LocationResult locationResult) {
lastLocation = locationResult.getLastLocation();
LocationInstance.getInstance().changeState(lastLocation);
saveLocation();
}
private void saveLocation() {
String saveLocation = getsaveLocationStatus(this);
if (saveLocation.equalsIgnoreCase("true") && notificationBuilder == 0) {
notificationBuilder();
notificationBuilder = 1;
} else if (saveLocation.equalsIgnoreCase("false") && notificationBuilder == 1) {
((NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE)).cancel(1);
notificationBuilder = 0;
}
Log.logd("receiveLocation : Share :- " + saveLocation + ", [Lat " + lastLocation.getLatitude() + ", Lng" + lastLocation.getLongitude() + "], Time :- " + mLastUpdateTime);
if (saveLocation.equalsIgnoreCase("true") || getPreviousMin() < getCurrentMin()) {
setLatLng(this, lastLocation);
mLastUpdateTime = DateFormat.getTimeInstance().format(new Date());
if (isOnline(this) && !getUserId(this).equalsIgnoreCase("")) {
if (!isInitRef) {
locationRef = getFirebaseInstance().child(getUserId(this)).child("location");
isInitRef = true;
}
if (isInitRef) {
locationRef.setValue(new LocationModel(lastLocation.getLatitude(), lastLocation.getLongitude(), mLastUpdateTime));
}
}
}
}
private int getPreviousMin() {
int previous_min = 0;
if (mLastUpdateTime != null) {
String[] pretime = mLastUpdateTime.split(":");
previous_min = Integer.parseInt(pretime[1].trim()) + 1;
if (previous_min > 59) {
previous_min = 0;
}
}
return previous_min;
}
@Override
public void onDestroy() {
super.onDestroy();
stopLocationUpdates();
}
/**
* Remove Location Update
*/
public void stopLocationUpdates() {
mFusedLocationClient
.removeLocationUpdates(mLocationCallback)
.addOnCompleteListener(task -> Log.logd("stopLocationUpdates : "));
}
private void notificationBuilder() {
if (Build.VERSION.SDK_INT >= 26) {
String CHANNEL_ID = "my_channel_01";
NotificationChannel channel = new NotificationChannel(CHANNEL_ID, "Channel human readable title",
NotificationManager.IMPORTANCE_DEFAULT);
((NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE)).createNotificationChannel(channel);
Notification notification = new NotificationCompat.Builder(this, CHANNEL_ID)
.setContentTitle("")
.setContentText("").build();
startForeground(1, notification);
}
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
}
Étape 3
<uses-permission Android:name="Android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission Android:name="Android.permission.ACCESS_FINE_LOCATION" />
<uses-permission Android:name="Android.permission.FOREGROUND_SERVICE" />
Étape 4
implementation 'com.google.Android.gms:play-services-location:16.0.0'
Toutes ces réponses ne fonctionnent pas de M-à - Android "O" - 8, en raison du mode Dozer qui restreint le service - quel que soit le service ou toute opération en arrière-plan nécessitant des éléments distincts en arrière-plan, il ne serait plus possible de fonctionner.
L’approche consiste donc à écouter le système FusedLocationApiClient via BroadCastReciever, qui écoute en permanence et fonctionne même en mode Doze.
Publier le lien serait inutile et recherchez FusedLocation with Broadcast receiver.
Merci