我正在使用geofencing api为我的校园创建一个考勤监控应用程序。其他一切工作正常,但我希望我的应用程序在后台工作。(类似于音乐播放器)。目前,它仅在应用程序打开时才有效。这是我使用的服务类代码:
package com.app.androidkt.geofencing;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
public class BackgroundService extends Service{
MainActivity main;
public int onStartCommand(Intent intent, int flags, int startId) {
main.isMonitoring = true;
main.startGeofencing();
main.startLocationMonitor();
return Service.START_STICKY;
}
@Override
public IBinder onBind(Intent intent) {
//use this method to communicate with your activity
return null;
}
}
这是MainActivity.java:
package com.app.androidkt.geofencing;
import android.Manifest;
import android.app.PendingIntent;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.graphics.Color;
import android.location.Location;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.ActivityCompat;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GoogleApiAvailability;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.common.api.ResultCallback;
import com.google.android.gms.common.api.Status;
import com.google.android.gms.location.Geofence;
import com.google.android.gms.location.GeofencingRequest;
import com.google.android.gms.location.LocationListener;
import com.google.android.gms.location.LocationRequest;
import com.google.android.gms.location.LocationServices;
import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.OnMapReadyCallback;
import com.google.android.gms.maps.SupportMapFragment;
import com.google.android.gms.maps.model.Circle;
import com.google.android.gms.maps.model.CircleOptions;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.Marker;
import com.google.android.gms.maps.model.MarkerOptions;
public class MainActivity extends AppCompatActivity implements
OnMapReadyCallback, GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener{
private static final String TAG = "MainActivity";
private static final int REQUEST_LOCATION_PERMISSION_CODE = 101;
private GoogleMap googleMap;
private GeofencingRequest geofencingRequest;
public GoogleApiClient googleApiClient;
public boolean isMonitoring = false;
private MarkerOptions markerOptions;
private Marker currentLocationMarker;
private PendingIntent pendingIntent;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager()
.findFragmentById(R.id.map);
mapFragment.getMapAsync(this);
googleApiClient = new GoogleApiClient.Builder(this)
.addApi(LocationServices.API)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this).build();
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
!= PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION}, REQUEST_LOCATION_PERMISSION_CODE);
}
}
public void startLocationMonitor() {
Log.d(TAG, "start location monitor");
LocationRequest locationRequest = LocationRequest.create()
.setInterval(2000)
.setFastestInterval(1000)
.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
try {
LocationServices.FusedLocationApi.requestLocationUpdates(googleApiClient, locationRequest, new LocationListener() {
@Override
public void onLocationChanged(Location location) {
if (currentLocationMarker != null) {
currentLocationMarker.remove();
}
markerOptions = new MarkerOptions();
markerOptions.position(new LatLng(location.getLatitude(), location.getLongitude()));
markerOptions.title("Current Location");
currentLocationMarker = googleMap.addMarker(markerOptions);
Log.d(TAG, "Location Change Lat Lng " + location.getLatitude() + " " + location.getLongitude());
}
});
} catch (SecurityException e) {
Log.d(TAG, e.getMessage());
}
}
public void startGeofencing() {
Log.d(TAG, "Start geofencing monitoring call");
pendingIntent = getGeofencePendingIntent();
geofencingRequest = new GeofencingRequest.Builder()
.setInitialTrigger(Geofence.GEOFENCE_TRANSITION_ENTER)
.addGeofence(getGeofence())
.build();
if (!googleApiClient.isConnected()) {
Log.d(TAG, "Google API client not connected");
} else {
try {
LocationServices.GeofencingApi.addGeofences(googleApiClient, geofencingRequest, pendingIntent).setResultCallback(new ResultCallback<Status>() {
@Override
public void onResult(@NonNull Status status) {
if (status.isSuccess()) {
Log.d(TAG, "Successfully Geofencing Connected");
} else {
Log.d(TAG, "Failed to add Geofencing " + status.getStatus());
}
}
});
} catch (SecurityException e) {
Log.d(TAG, e.getMessage());
}
}
isMonitoring = true;
invalidateOptionsMenu();
}
@NonNull
public Geofence getGeofence() {
LatLng latLng = Constants.AREA_LANDMARKS.get(Constants.GEOFENCE_ID_STAN_UNI);
return new Geofence.Builder()
.setRequestId(Constants.GEOFENCE_ID_STAN_UNI)
.setExpirationDuration(Geofence.NEVER_EXPIRE)
.setCircularRegion(latLng.latitude, latLng.longitude, Constants.GEOFENCE_RADIUS_IN_METERS)
.setNotificationResponsiveness(1000)
.setTransitionTypes(Geofence.GEOFENCE_TRANSITION_ENTER | Geofence.GEOFENCE_TRANSITION_EXIT)
.build();
}
public PendingIntent getGeofencePendingIntent() {
if (pendingIntent != null) {
return pendingIntent;
}
Intent intent = new Intent(this, GeofenceRegistrationService.class);
return PendingIntent.getService(this, 0, intent, PendingIntent.
FLAG_UPDATE_CURRENT);
}
private void stopGeoFencing() {
pendingIntent = getGeofencePendingIntent();
LocationServices.GeofencingApi.removeGeofences(googleApiClient, pendingIntent)
.setResultCallback(new ResultCallback<Status>() {
@Override
public void onResult(@NonNull Status status) {
if (status.isSuccess())
Log.d(TAG, "Stop geofencing");
else
Log.d(TAG, "Not stop geofencing");
}
});
isMonitoring = false;
invalidateOptionsMenu();
}
@Override
protected void onResume() {
super.onResume();
int response = GoogleApiAvailability.getInstance().isGooglePlayServicesAvailable(MainActivity.this);
if (response != ConnectionResult.SUCCESS) {
Log.d(TAG, "Google Play Service Not Available");
GoogleApiAvailability.getInstance().getErrorDialog(MainActivity.this, response, 1).show();
} else {
Log.d(TAG, "Google play service available");
}
}
@Override
protected void onStart() {
super.onStart();
googleApiClient.reconnect();
}
@Override
protected void onStop() {
super.onStop();
googleApiClient.disconnect();
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.manu_map_activity, menu);
if (isMonitoring) {
menu.findItem(R.id.action_start_monitor).setVisible(false);
menu.findItem(R.id.action_stop_monitor).setVisible(true);
menu.findItem(R.id.startservice).setVisible(true);
} else {
menu.findItem(R.id.action_start_monitor).setVisible(true);
menu.findItem(R.id.action_stop_monitor).setVisible(false);
}
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.action_start_monitor:
startGeofencing();
break;
case R.id.action_stop_monitor:
stopGeoFencing();
break;
case R.id.startservice:
startService(new Intent(this, BackgroundService.class));
break;
}
return super.onOptionsItemSelected(item);
}
@Override
protected void onDestroy() {
super.onDestroy();
}
@Override
public void onMapReady(GoogleMap googleMap) {
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
return;
}
this.googleMap = googleMap;
LatLng latLng = Constants.AREA_LANDMARKS.get(Constants.GEOFENCE_ID_STAN_UNI);
googleMap.addMarker(new MarkerOptions().position(latLng).title("Stanford University"));
googleMap.moveCamera(CameraUpdateFactory.newLatLngZoom(latLng, 17f));
googleMap.setMyLocationEnabled(true);
Circle circle = googleMap.addCircle(new CircleOptions()
.center(new LatLng(latLng.latitude, latLng.longitude))
.radius(Constants.GEOFENCE_RADIUS_IN_METERS)
.strokeColor(Color.RED)
.strokeWidth(4f));
}
@Override
public void onConnected(@Nullable Bundle bundle) {
Log.d(TAG, "Google Api Client Connected");
isMonitoring = true;
startGeofencing();
startLocationMonitor();
}
@Override
public void onConnectionSuspended(int i) {
Log.d(TAG, "Google Connection Suspended");
}
@Override
public void onConnectionFailed(@NonNull ConnectionResult connectionResult) {
isMonitoring = false;
Log.e(TAG, "Connection Failed:" + connectionResult.getErrorMessage());
}
}
当我尝试通过单击我在应用程序中提供的背景选项在后台运行应用程序时,应用程序崩溃并且我收到运行时错误说:
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.app.androidkt.geofencing, PID: 24176
java.lang.RuntimeException: Unable to start service com.app.androidkt.geofencing.BackgroundService@52135c5 with Intent { cmp=com.app.androidkt.geofencing/.BackgroundService }: java.lang.NullPointerException: Attempt to write to field 'boolean com.app.androidkt.geofencing.MainActivity.isMonitoring' on a null object reference
at android.app.ActivityThread.handleServiceArgs(ActivityThread.java:3335)
at android.app.ActivityThread.-wrap21(ActivityThread.java)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1578)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6123)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:867)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:757)
Caused by: java.lang.NullPointerException: Attempt to write to field 'boolean com.app.androidkt.geofencing.MainActivity.isMonitoring' on a null object reference
at com.app.androidkt.geofencing.BackgroundService.onStartCommand(BackgroundService.java:13)
at android.app.ActivityThread.handleServiceArgs(ActivityThread.java:3318)
at android.app.ActivityThread.-wrap21(ActivityThread.java)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1578)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6123)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:867)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:757)
请建议我修改代码。