J'essaie de créer une clôture géographique avec un service d'arrière-plan pour le moniteur. La clôture géographique crée avec succès et fonctionne lorsque l'activité des applications est ouverte, mais lorsqu'elle est fermée, la clôture géographique de l'application ne fonctionne pas. Qu'est-ce que je devrais faire maintenant. Mon code est:
public class MapsActivity extends FragmentActivity implements OnMapReadyCallback,
GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener,
LocationListener {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_maps);
// Obtain the SupportMapFragment and get notified when the map is ready to be used.
SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager()
.findFragmentById(R.id.map);
mapFragment.getMapAsync(this);
ref = FirebaseDatabase.getInstance().getReference("MyLocation");
geoFire = new GeoFire(ref);
mVerticalSeekBar = (VerticalSeekBar)findViewById(R.id.verticalSeekBar);
setUpdateLocation();
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
switch (requestCode) {
case MY_PERMISSION_REQUEST_CODE:
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
if (checkPlayService()) {
buildGoogleApiClient();
createLocationRequest();
displayLocation();
}
}
break;
}
}
private void setUpdateLocation() {
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED &&
ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, new String[]{
Manifest.permission.ACCESS_COARSE_LOCATION,
Manifest.permission.ACCESS_FINE_LOCATION
}, MY_PERMISSION_REQUEST_CODE);
} else {
if (checkPlayService()) {
buildGoogleApiClient();
createLocationRequest();
displayLocation();
}
}
}
private void displayLocation() {
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED &&
ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
return;
}
mLastLocaiton = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
if (mLastLocaiton != null) {
final double latitude = mLastLocaiton.getLatitude();
final double longitude = mLastLocaiton.getLongitude();
geoFire.setLocation("You", new GeoLocation(latitude, longitude), new GeoFire.CompletionListener() {
@Override
public void onComplete(String key, DatabaseError error) {
if (mCurrent != null)
mCurrent.remove();
mCurrent = mMap.addMarker(new MarkerOptions()
.position(new LatLng(latitude, longitude))
.title("You"));
LatLng coordinate = new LatLng(latitude, longitude);
CameraUpdate yourLocation = CameraUpdateFactory.newLatLngZoom(coordinate, 12);
mMap.animateCamera(yourLocation);
}
});
Log.d("MRF", String.format("Your last location was chaged: %f / %f", latitude, longitude));
} else {
Log.d("MRF", "Can not get your location.");
}
}
private void createLocationRequest() {
mLocationRequest = new LocationRequest();
mLocationRequest.setInterval(UPDATE_INTERVAL);
mLocationRequest.setFastestInterval(FATEST_INTERVAL);
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
mLocationRequest.setSmallestDisplacement(DISPLACEMENT);
}
private void buildGoogleApiClient() {
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API).build();
mGoogleApiClient.connect();
}
private boolean checkPlayService() {
GoogleApiAvailability googleAPI = GoogleApiAvailability.getInstance();
int result = googleAPI.isGooglePlayServicesAvailable(this);
if (result != ConnectionResult.SUCCESS) {
if (googleAPI.isUserResolvableError(result)) {
googleAPI.getErrorDialog(this, result, PLAY_SERVICE_RESULATION_REQUEST).show();
} else {
Toast.makeText(this, "This Device is not supported.", Toast.LENGTH_SHORT).show();
}
return false;
}
return true;
}
@Override
public void onMapReady(GoogleMap googleMap) {
mMap = googleMap;
LatLng dangerous_area = new LatLng(23.7424236, 90.3942189);
mMap.addCircle(new CircleOptions()
.center(dangerous_area)
.radius(100)
.strokeColor(Color.BLUE)
.fillColor(0x220000FF)
.strokeWidth(5.0f));
//add GeoQuery here
GeoQuery geoQuery = geoFire.queryAtLocation(new GeoLocation(dangerous_area.latitude, dangerous_area.longitude), 0.1f);
geoQuery.addGeoQueryEventListener(new GeoQueryEventListener() {
@Override
public void onKeyEntered(String key, GeoLocation location) {
sendNotification("MRF", String.format("%s entered the dangerous area",key));
}
@Override
public void onKeyExited(String key) {
sendNotification("MRF", String.format("%s exit the dangerous area",key));
}
@Override
public void onKeyMoved(String key, GeoLocation location) {
Log.d("MOVE", String.format("%s move within the dangerous area [%f/%f]", key, location.latitude, location.longitude));
}
@Override
public void onGeoQueryReady() {
}
@Override
public void onGeoQueryError(DatabaseError error) {
Log.d("ERROR", ""+error);
}
});
}
private void sendNotification(String title, String content) {
Notification.Builder builder = new Notification.Builder(this)
.setSmallIcon(R.mipmap.ic_launcher)
.setContentTitle(title)
.setContentText(content);
NotificationManager manager = (NotificationManager)this.getSystemService(Context.NOTIFICATION_SERVICE);
Intent intent = new Intent(this, MapsActivity.class);
PendingIntent contentIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_IMMUTABLE);
builder.setContentIntent(contentIntent);
Notification notification = builder.build();
notification.flags |= Notification.FLAG_AUTO_CANCEL;
notification.defaults |= Notification.DEFAULT_SOUND;
manager.notify(new Random().nextInt(), notification);
}
@Override
public void onConnected(@Nullable Bundle bundle) {
displayLocation();
startLocationUpdate();
}
private void startLocationUpdate() {
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED &&
ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
return;
}
LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, this);
}
@Override
public void onConnectionSuspended(int i) {
mGoogleApiClient.connect();
}
@Override
public void onConnectionFailed(@NonNull ConnectionResult connectionResult) {
}
@Override
public void onLocationChanged(Location location) {
mLastLocaiton = location;
displayLocation();
}
le lien github est: https://github.com/Farhad2015/Geofence-GeoFire/blob/master/app/src/main/Java/com/mahmud/geotesting/MapsActivity.Java
Veuillez m'aider à créer un service d'arrière-plan pour surveiller la clôture géographique à partir d'arrière-plan.
De Android Oreo, vous ne pouvez pas créer un service de longue durée en tant que service d'arrière-plan. Vous devez donc créer un service de premier plan que le service doit lier à l'activité en cours
Un autre problème est la mise à jour de l'emplacement. Lorsque vous utilisez geoQuery
dans un service, vous devez également mettre à jour l'emplacement dans le service. Lorsqu'un déclencheur de mise à jour d'emplacement doit passer cette mise à jour à l'activité, seule l'interface utilisateur peut être mise à jour. Dans ma solution, j'utilise une interface pour mettre à jour l'interface utilisateur. Vous pouvez également utiliser des écouteurs de diffusion.
Lorsque vous créez un service et le liez à une activité, vous pouvez utiliser Geofence à l'intérieur du service
public void startService(LatLng latLng, double radius) {
if (!isServiceRunning) {
isServiceRunning = true;
} else {
Log.e(TAG, "startTimer request for an already running timer");
}
if (geoQuery!=null){
geoQuery.removeAllListeners();
}
geoQuery = geoFire.queryAtLocation(new GeoLocation(latLng.latitude, latLng.longitude), 2f);
geoQuery.addGeoQueryEventListener(new GeoQueryEventListener() {
@Override
public void onKeyEntered(String key, GeoLocation location) {
sendNotification("MRF", String.format("%s entered the dangerous area", key));
}
@Override
public void onKeyExited(String key) {
sendNotification("MRF", String.format("%s exit the dangerous area", key));
}
@Override
public void onKeyMoved(String key, GeoLocation location) {
Log.d("MOVE", String.format("%s move within the dangerous area [%f/%f]", key, location.latitude, location.longitude));
}
@Override
public void onGeoQueryReady() {
}
@Override
public void onGeoQueryError(DatabaseError error) {
Log.d("ERROR", "" + error);
}
});
}
Vous pouvez appeler cette méthode depuis votre activité comme
geoService.startService(dangerous_area,2000);
Cela fonctionnera même si votre application est détruite.
Le code complet est le suivant
public class MapsActivity extends FragmentActivity implements OnMapReadyCallback {
private GoogleMap mMap;
//Play Service Location
private static final int MY_PERMISSION_REQUEST_CODE = 7192;
private static final int PLAY_SERVICE_RESULATION_REQUEST = 300193;
private Location mLastLocaiton;
private static int UPDATE_INTERVAL = 5000;
private static int FATEST_INTERVAL = 3000;
private static int DISPLACEMENT = 10;
Marker mCurrent;
VerticalSeekBar mVerticalSeekBar;
private static final String TAG = MapsActivity.class.getSimpleName();
private GeoService geoService;
private boolean serviceBound;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_maps);
// Obtain the SupportMapFragment and get notified when the map is ready to be used.
mVerticalSeekBar = (VerticalSeekBar) findViewById(R.id.verticalSeekBar);
mVerticalSeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
mMap.animateCamera(CameraUpdateFactory.zoomTo(progress), 1500, null);
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
}
});
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
switch (requestCode) {
case MY_PERMISSION_REQUEST_CODE:
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
if (checkPlayService()) {
geoService.buildGoogleApiClient();
geoService.createLocationRequest();
geoService.displayLocation();
geoService.setLocationChangeListener(new GeoService.LocationChangeListener() {
@Override
public void onLocationChange(Location location) {
if (mCurrent != null)
mCurrent.remove();
mCurrent = mMap.addMarker(new MarkerOptions()
.position(new LatLng(location.getLatitude(), location.getLongitude()))
.title("You"));
LatLng coordinate = new LatLng(location.getLatitude(), location.getLongitude());
CameraUpdate yourLocation = CameraUpdateFactory.newLatLngZoom(coordinate, 12);
mMap.animateCamera(yourLocation);
}
});
}
}
break;
}
}
private void setUpdateLocation() {
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED &&
ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, new String[]{
Manifest.permission.ACCESS_COARSE_LOCATION,
Manifest.permission.ACCESS_FINE_LOCATION
}, MY_PERMISSION_REQUEST_CODE);
} else {
if (checkPlayService()) {
geoService.buildGoogleApiClient();
geoService.createLocationRequest();
geoService.displayLocation();
geoService.setLocationChangeListener(new GeoService.LocationChangeListener() {
@Override
public void onLocationChange(Location location) {
if (mCurrent != null)
mCurrent.remove();
mCurrent = mMap.addMarker(new MarkerOptions()
.position(new LatLng(location.getLatitude(), location.getLongitude()))
.title("You"));
LatLng coordinate = new LatLng(location.getLatitude(), location.getLongitude());
CameraUpdate yourLocation = CameraUpdateFactory.newLatLngZoom(coordinate, 12);
mMap.animateCamera(yourLocation);
}
});
}
}
}
private boolean checkPlayService() {
GoogleApiAvailability googleAPI = GoogleApiAvailability.getInstance();
int result = googleAPI.isGooglePlayServicesAvailable(this);
if (result != ConnectionResult.SUCCESS) {
if (googleAPI.isUserResolvableError(result)) {
googleAPI.getErrorDialog(this, result, PLAY_SERVICE_RESULATION_REQUEST).show();
} else {
Toast.makeText(this, "This Device is not supported.", Toast.LENGTH_SHORT).show();
}
return false;
}
return true;
}
@Override
public void onMapReady(GoogleMap googleMap) {
mMap = googleMap;
LatLng dangerous_area = new LatLng(8.5324236, 76.8842189);
mMap.addCircle(new CircleOptions()
.center(dangerous_area)
.radius(2000)
.strokeColor(Color.BLUE)
.fillColor(0x220000FF)
.strokeWidth(5.0f));
geoService.startService(dangerous_area,2000);
}
@Override
protected void onStart() {
super.onStart();
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "Starting and binding service");
}
Intent i = new Intent(this, GeoService.class);
startService(i);
bindService(i, mConnection, 0);
}
@Override
protected void onStop() {
super.onStop();
if (serviceBound) {
// If a timer is active, foreground the service, otherwise kill the service
if (geoService.isServiceRunning()) {
geoService.foreground();
} else {
stopService(new Intent(this, GeoService.class));
}
// Unbind the service
unbindService(mConnection);
serviceBound = false;
}
}
/**
* Callback for service binding, passed to bindService()
*/
private ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName className, IBinder service) {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "Service bound");
}
GeoService.RunServiceBinder binder = (GeoService.RunServiceBinder) service;
geoService = binder.getService();
serviceBound = true;
// Ensure the service is not in the foreground when bound
geoService.background();
setUpdateLocation();
SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager()
.findFragmentById(R.id.map);
mapFragment.getMapAsync(MapsActivity.this);
}
@Override
public void onServiceDisconnected(ComponentName name) {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "Service disconnect");
}
serviceBound = false;
}
};
public static class GeoService extends Service implements GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener,
LocationListener {
private LocationRequest mLocationRequest;
private GoogleApiClient mGoogleApiClient;
private Location mLastLocation;
private DatabaseReference ref;
private GeoFire geoFire;
private LocationChangeListener mLocationChangeListener;
private static final String TAG = GeoService.class.getSimpleName();
// Is the service tracking time?
private boolean isServiceRunning;
// Foreground notification id
private static final int NOTIFICATION_ID = 1;
// Service binder
private final IBinder serviceBinder = new RunServiceBinder();
private GeoQuery geoQuery;
public class RunServiceBinder extends Binder {
GeoService getService() {
return GeoService.this;
}
}
@Override
public void onCreate() {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "Creating service");
}
ref = FirebaseDatabase.getInstance().getReference("MyLocation");
geoFire = new GeoFire(ref);
isServiceRunning = false;
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "Starting service");
}
return Service.START_STICKY;
}
@Override
public IBinder onBind(Intent intent) {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "Binding service");
}
return serviceBinder;
}
@Override
public void onDestroy() {
super.onDestroy();
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "Destroying service");
}
}
/**
* Starts the timer
*/
public void startService(LatLng latLng, double radius) {
if (!isServiceRunning) {
isServiceRunning = true;
} else {
Log.e(TAG, "startService request for an already running Service");
}
if (geoQuery!=null){
geoQuery.removeAllListeners();
}
geoQuery = geoFire.queryAtLocation(new GeoLocation(latLng.latitude, latLng.longitude), 2f);
geoQuery.addGeoQueryEventListener(new GeoQueryEventListener() {
@Override
public void onKeyEntered(String key, GeoLocation location) {
sendNotification("MRF", String.format("%s entered the dangerous area", key));
}
@Override
public void onKeyExited(String key) {
sendNotification("MRF", String.format("%s exit the dangerous area", key));
}
@Override
public void onKeyMoved(String key, GeoLocation location) {
Log.d("MOVE", String.format("%s move within the dangerous area [%f/%f]", key, location.latitude, location.longitude));
}
@Override
public void onGeoQueryReady() {
}
@Override
public void onGeoQueryError(DatabaseError error) {
Log.d("ERROR", "" + error);
}
});
}
/**
* Stops the timer
*/
public void stopService() {
if (isServiceRunning) {
isServiceRunning = false;
geoQuery.removeAllListeners();
} else {
Log.e(TAG, "stopTimer request for a timer that isn't running");
}
}
/**
* @return whether the service is running
*/
public boolean isServiceRunning() {
return isServiceRunning;
}
/**
* Place the service into the foreground
*/
public void foreground() {
startForeground(NOTIFICATION_ID, createNotification());
}
/**
* Return the service to the background
*/
public void background() {
stopForeground(true);
}
/**
* Creates a notification for placing the service into the foreground
*
* @return a notification for interacting with the service when in the foreground
*/
private Notification createNotification() {
NotificationCompat.Builder builder = new NotificationCompat.Builder(this)
.setContentTitle("Service is Active")
.setContentText("Tap to return to the Map")
.setSmallIcon(R.mipmap.ic_launcher);
Intent resultIntent = new Intent(this, MapsActivity.class);
PendingIntent resultPendingIntent =
PendingIntent.getActivity(this, 0, resultIntent,
PendingIntent.FLAG_UPDATE_CURRENT);
builder.setContentIntent(resultPendingIntent);
return builder.build();
}
private void sendNotification(String title, String content) {
Notification.Builder builder = new Notification.Builder(this)
.setSmallIcon(R.mipmap.ic_launcher)
.setContentTitle(title)
.setContentText(content);
NotificationManager manager = (NotificationManager) this.getSystemService(Context.NOTIFICATION_SERVICE);
Intent intent = new Intent(this, MapsActivity.class);
PendingIntent contentIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_IMMUTABLE);
builder.setContentIntent(contentIntent);
Notification notification = builder.build();
notification.flags |= Notification.FLAG_AUTO_CANCEL;
notification.defaults |= Notification.DEFAULT_SOUND;
manager.notify(new Random().nextInt(), notification);
}
@Override
public void onConnected(@Nullable Bundle bundle) {
displayLocation();
startLocationUpdate();
}
private void startLocationUpdate() {
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED &&
ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
return;
}
LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, this);
}
@Override
public void onConnectionSuspended(int i) {
mGoogleApiClient.connect();
}
@Override
public void onConnectionFailed(@NonNull ConnectionResult connectionResult) {
}
@Override
public void onLocationChanged(Location location) {
mLastLocation = location;
displayLocation();
}
interface LocationChangeListener {
void onLocationChange(Location location);
}
private void createLocationRequest() {
mLocationRequest = new LocationRequest();
mLocationRequest.setInterval(UPDATE_INTERVAL);
mLocationRequest.setFastestInterval(FATEST_INTERVAL);
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
mLocationRequest.setSmallestDisplacement(DISPLACEMENT);
}
private void buildGoogleApiClient() {
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API).build();
mGoogleApiClient.connect();
}
private void displayLocation() {
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED &&
ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
return;
}
mLastLocation = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
if (mLastLocation != null) {
final double latitude = mLastLocation.getLatitude();
final double longitude = mLastLocation.getLongitude();
geoFire.setLocation("You", new GeoLocation(latitude, longitude), new GeoFire.CompletionListener() {
@Override
public void onComplete(String key, DatabaseError error) {
if (mLocationChangeListener!=null) {
mLocationChangeListener.onLocationChange(mLastLocation);
}
}
});
Log.d("MRF", String.format("Your last location was chaged: %f / %f", latitude, longitude));
} else {
Log.d("MRF", "Can not get your location.");
}
}
public void setLocationChangeListener(LocationChangeListener mLocationChangeListener) {
this.mLocationChangeListener = mLocationChangeListener;
}
}
}
N'oubliez pas d'ajouter un service au manifeste
<service Android:name=".MapsActivity$GeoService" />
Code source complet github.com/vinayakb73/GeoFence-GeoFire