如何在后台运行地理围栏应用程序?

时间:2018-04-16 17:50:49

标签: android service geofencing

我正在使用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) 

请建议我修改代码。

1 个答案:

答案 0 :(得分:0)

go

未在BackgroundService中初始化。

尝试实现界面,而不是像这样访问Activity的方法。

选中此answer以实现界面。