モニター用のバックグラウンドサービスを備えたジオフェンスを作成しようとしています。ジオフェンスは正常に作成され、アプリのアクティビティが開いているときに機能しますが、アプリのジオフェンスを閉じると機能しません。私は今どうすればいい。私のコードは:
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();
}
バックグラウンドからジオフェンスを監視するためのバックグラウンドサービスの作成を手伝ってください。
Android Oreoからは、バックグラウンドサービスとして長時間実行サービスを作成することはできません。そのため、サービスが現在のアクティビティにバインドする必要があるフォアグラウンドサービスを作成する必要があります
別の問題は、場所の更新です。サービス内でgeoQuery
を使用する場合は、サービス内でも場所を更新する必要があります。場所の更新がトリガーされると、この更新をアクティビティに渡す必要があります。そうすると、UIのみが更新できます。私のソリューションでは、インターフェイスを使用してUIを更新しています。ブロードキャストリスナーを使用することもできます。
サービスを作成してアクティビティにバインドすると、サービス内でジオフェンスを使用できます
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);
}
});
}
あなたはあなたの活動からこのメソッドを呼び出すことができます
geoService.startService(dangerous_area,2000);
これは、アプリが破壊されても機能します。
完全なコードは次のとおりです
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;
}
}
}
マニフェストにサービスを追加することを忘れないでください
<service Android:name=".MapsActivity$GeoService" />
完全なソースコード github.com/vinayakb73/GeoFence-GeoFire