我正在创建一个Android应用程序,希望在我的服务器上指定的LatLong坐标处创建Geofence。
坐标会在服务中的后台定期更新。我正在阅读这些坐标,并希望在没有用户干预的情况下在后台创建地理围栏。我尝试在服务中这样做,但它不起作用。我可以定期从服务器获取坐标,但是我无法为它创建Geofence,获得nullPointerException。
但是,我可以通过单击按钮(硬编码LatLong坐标)在活动中创建Geofences,但它无法在服务中使用。
我的服务:
public class GPSPollingService extends Service implements ResultCallback<Status>, GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener, LocationListener {
private GoogleApiClient mGoogleApiClient;
private PowerManager.WakeLock mWakeLock;
private LocationRequest mLocationRequest;
// Flag that indicates if a request is underway.
private boolean mInProgress;
private final String TAG = "GPSPollingService";
private PendingIntent mGeofencePendingIntent;
String url = "http://shielded.coolpage.biz/status_read.php";
private static final int REQUEST_CODE_LOCATION = 2;
private Boolean servicesAvailable = false;
private Activity mActivity;
ArrayList<Geofence> mCurrentGeofences = new ArrayList<Geofence>();;
RequestQueue requestQueue;
Location mLocation;
public GPSPollingService(){}
public GPSPollingService(Activity mActivity){
super();
this.mActivity = mActivity;
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onCreate() {
super.onCreate();
mInProgress = false;
requestQueue = Volley.newRequestQueue(this);
// Instantiate the current List of geofences
mCurrentGeofences = new ArrayList<Geofence>();
mGeofencePendingIntent = null;
setUpLocationClientIfNeeded();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
super.onStartCommand(intent, flags, startId);
mGoogleApiClient.connect();
Log.d(TAG,"onStartCommand: ");
PowerManager mgr = (PowerManager)getSystemService(Context.POWER_SERVICE);
/*
WakeLock is reference counted so we don't want to create multiple WakeLocks. So do a check before initializing and acquiring.
This will fix the "java.lang.Exception: WakeLock finalized while still held: MyWakeLock" error that you may find.
*/
if (this.mWakeLock == null) { //**Added this
this.mWakeLock = mgr.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "MyWakeLock");
}
if (!this.mWakeLock.isHeld()) { //**Added this
this.mWakeLock.acquire();
}
if(!servicesAvailable || mGoogleApiClient.isConnected() || mInProgress)
return START_STICKY;
setUpLocationClientIfNeeded();
if(!mGoogleApiClient.isConnected() || !mGoogleApiClient.isConnecting() && !mInProgress)
{
//appendLog(DateFormat.getDateTimeInstance().format(new Date()) + ": Started", Constants.LOG_FILE);
mInProgress = true;
mGoogleApiClient.connect();
}
return START_STICKY;
}
private void setUpLocationClientIfNeeded()
{
if(mGoogleApiClient == null)
googleApiClientBuild();
}
protected synchronized void googleApiClientBuild(){
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addApi(LocationServices.API)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.build();
}
@Override
public void onConnected(@Nullable Bundle bundle) {
mLocationRequest = LocationRequest.create();
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
mLocationRequest.setInterval(120000); // Update location every 60 seconds
Log.d(TAG,"in onConnected: ");
if ( ContextCompat.checkSelfPermission( this, android.Manifest.permission.ACCESS_FINE_LOCATION ) != PackageManager.PERMISSION_GRANTED ) {
ActivityCompat.requestPermissions( mActivity, new String[] { android.Manifest.permission.ACCESS_COARSE_LOCATION },
REQUEST_CODE_LOCATION );
}else {
LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, this);
//Location mLocation = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
//txtOutput.setText(mLocation.toString());
Log.d(TAG, "calling fusedLocationApi");
}
continueAddGeofences();
}
@Override
public void onConnectionSuspended(int i) {
// Turn off the request flag
mInProgress = false;
// Destroy the current location client
mGoogleApiClient = null;
Log.d(TAG, "onConnectionSuspended ");
}
@Override
public void onLocationChanged(Location location) {
mLocation = location;
Log.d(TAG,"in onLocationChanged: ");
Log.d(TAG, mLocation.toString());
// save new location to db
connectToDb(); // checking for status 1
}
@Override
public void onConnectionFailed(@NonNull ConnectionResult connectionResult) {
mInProgress = false;
Log.d(TAG, "onConnectionFailed");
/*
* Google Play services can resolve some errors it detects.
* If the error has a resolution, try sending an Intent to
* start a Google Play services activity that can resolve
* error.
*/
if (connectionResult.hasResolution()) {
Log.d(TAG, "google play services has solution");
// If no resolution is available, display an error dialog
} else {
Log.d(TAG, "no solution for connection failure");
}
}
@Override
public void onDestroy() {
// Turn off the request flag
this.mInProgress = false;
if (this.servicesAvailable && this.mGoogleApiClient != null) {
this.mGoogleApiClient.unregisterConnectionCallbacks(this);
this.mGoogleApiClient.unregisterConnectionFailedListener(this);
this.mGoogleApiClient.disconnect();
// Destroy the current location client
this.mGoogleApiClient = null;
}
// Display the connection status
// Toast.makeText(this, DateFormat.getDateTimeInstance().format(new Date()) + ":
// Disconnected. Please re-connect.", Toast.LENGTH_SHORT).show();
if (this.mWakeLock != null) {
this.mWakeLock.release();
this.mWakeLock = null;
}
super.onDestroy();
}
public void connectToDb(){
StringRequest stringRequest = new StringRequest(Request.Method.POST, url, new Response.Listener<String>() {
@Override
public void onResponse(String s) {
Toast.makeText(getApplicationContext() , ""+s,Toast.LENGTH_LONG).show();
Log.d(TAG, ""+s);
try {
JSONObject jsonObject = new JSONObject(s);
JSONArray jsonArray = jsonObject.getJSONArray("result");
if(jsonArray.length()!=0){
Log.d(TAG,"array length not 0");
JSONObject personInDanger = jsonArray.getJSONObject(0);
setGeofence(Double.valueOf(personInDanger.getString("latitude")), Double.valueOf(personInDanger.getString("longitude")));
}
}catch (JSONException je) {
// do something with it
}
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError volleyError) {
Toast.makeText(getApplicationContext(), ""+volleyError, Toast.LENGTH_LONG).show();
}
});
requestQueue.add(stringRequest);
}
/**
* Verify that Google Play services is available before making a request.
*
* @return true if Google Play services is available, otherwise false
*/
private boolean servicesConnected() {
// Check that Google Play services is available
int resultCode = GooglePlayServicesUtil.isGooglePlayServicesAvailable(this);
// If Google Play services is available
if (ConnectionResult.SUCCESS == resultCode) {
// In debug mode, log the status
Log.d(GeofenceUtils.APPTAG, getString(R.string.play_services_available));
// Continue
return true;
// Google Play services was not available for some reason
} else {
// Display an error dialog
Toast.makeText(getApplicationContext(), "Google play services not available", Toast.LENGTH_SHORT).show();
//Dialog dialog = GooglePlayServicesUtil.getErrorDialog(resultCode, (Activity) getApplicationContext(), 0);
//if (dialog != null) {
// ErrorDialogFragment errorFragment = new ErrorDialogFragment();
// errorFragment.setDialog(dialog);
// errorFragment.show(getSupportFragmentManager(), GeofenceUtils.APPTAG);
}
return false;
}
public void setGeofence(Double latitude , Double longitude){
Log.d(TAG, "in setGeofence");
if (!servicesConnected()) {
return;
}
SimpleGeofence newGeofence = new SimpleGeofence(
"1",
// Get latitude, longitude, and radius from the db
latitude,
longitude,
Float.valueOf("50.0"),
// Set the expiration time
Geofence.NEVER_EXPIRE,
// Detect both entry and exit transitions
Geofence.GEOFENCE_TRANSITION_ENTER
);
mCurrentGeofences.add(newGeofence.toGeofence());
// Start the request. Fail if there's already a request in progress
try {
// Try to add geofences
addGeofences(mCurrentGeofences);
} catch (UnsupportedOperationException e) {
// Notify user that previous request hasn't finished.
Toast.makeText(this, R.string.add_geofences_already_requested_error,
Toast.LENGTH_LONG).show();
}
}
public void addGeofences(ArrayList<Geofence> geofences) throws UnsupportedOperationException {
if (!mInProgress) {
// Toggle the flag and continue
mInProgress = true;
// Request a connection to Location Services
requestConnection();
// If a request is in progress
} else {
// Throw an exception and stop the request
throw new UnsupportedOperationException();
}
}
private void requestConnection() {
getLocationClient().connect();
}
private GoogleApiClient getLocationClient() {
if (mGoogleApiClient == null) {
mGoogleApiClient = new GoogleApiClient.Builder(mActivity)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
}
return mGoogleApiClient;
}
private void continueAddGeofences() {
// Get a PendingIntent that Location Services issues when a geofence transition occurs
mGeofencePendingIntent = createRequestPendingIntent();
if (!mGoogleApiClient.isConnected()) {
Toast.makeText(mActivity, "not connected", Toast.LENGTH_SHORT).show();
return;
}
try {
LocationServices.GeofencingApi.addGeofences(
mGoogleApiClient,
// The GeofenceRequest object.
mCurrentGeofences,
// A pending intent that that is reused when calling removeGeofences(). This
// pending intent is used to generate an intent when a matched geofence
// transition is observed.
mGeofencePendingIntent
).setResultCallback(this); // Result processed in onResult().
} catch (SecurityException securityException) {
// Catch exception generated if the app does not use ACCESS_FINE_LOCATION permission.
logSecurityException(securityException);
}
}
private void logSecurityException(SecurityException securityException) {
Log.e(GeofenceUtils.APPTAG , "Invalid location permission. " +
"You need to use ACCESS_FINE_LOCATION with geofences", securityException);
}
public void onResult(Status status) {
Intent broadcastIntent = new Intent();
// Temp storage for messages
String msg;
if (status.isSuccess()) {
Toast.makeText(
mActivity, "Geofences added",
Toast.LENGTH_SHORT
).show();
msg = mActivity.getString(R.string.add_geofences_result_success, status);
// In debug mode, log the result
Log.d(GeofenceUtils.APPTAG, msg);
// Create an Intent to broadcast to the app
broadcastIntent.setAction(GeofenceUtils.ACTION_GEOFENCES_ADDED)
.addCategory(GeofenceUtils.CATEGORY_LOCATION_SERVICES)
.putExtra(GeofenceUtils.EXTRA_GEOFENCE_STATUS, msg);
// If adding the geofences failed
} else {
/*
* Create a message containing the error code and the list
* of geofence IDs you tried to add
*/
msg = mActivity.getString(
R.string.add_geofences_result_failure,
status.getStatusCode(), status.getStatusMessage());
// Log an error
Log.e(GeofenceUtils.APPTAG, msg);
}
}
private PendingIntent createRequestPendingIntent() {
// If the PendingIntent already exists
if (null != mGeofencePendingIntent) {
// Return the existing intent
return mGeofencePendingIntent;
// If no PendingIntent exists
} else {
Intent intent = new Intent("com.example.android.geofence.ACTION_RECEIVE_GEOFENCE");
return PendingIntent.getBroadcast(
mActivity,
0,
intent,
PendingIntent.FLAG_UPDATE_CURRENT);
}
}
}
我的日志:
java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String android.content.Context.getPackageName()' on a null object reference
at android.app.PendingIntent.getBroadcastAsUser(PendingIntent.java:506)
at android.app.PendingIntent.getBroadcast(PendingIntent.java:495)
at com.example.android.safetyalert.GPSPollingService.createRequestPendingIntent(GPSPollingService.java:449)
at com.example.android.safetyalert.GPSPollingService.continueAddGeofences(GPSPollingService.java:369)
at com.example.android.safetyalert.GPSPollingService.onConnected(GPSPollingService.java:163)
at com.google.android.gms.common.internal.zzl.zzm(Unknown Source)
at com.google.android.gms.internal.zzof.zzk(Unknown Source)
at com.google.android.gms.internal.zzod.zzsb(Unknown Source)
at com.google.android.gms.internal.zzod.onConnected(Unknown Source)
at com.google.android.gms.internal.zzoh.onConnected(Unknown Source)
at com.google.android.gms.internal.zznw.onConnected(Unknown Source)
at com.google.android.gms.common.internal.zzk$1.onConnected(Unknown Source)
at com.google.android.gms.common.internal.zzd$zzj.zztp(Unknown Source)
at com.google.android.gms.common.internal.zzd$zza.zzc(Unknown Source)
at com.google.android.gms.common.internal.zzd$zza.zzw(Unknown Source)
at com.google.android.gms.common.internal.zzd$zze.zztr(Unknown Source)
at com.google.android.gms.common.internal.zzd$zzd.handleMessage(Unknown Source)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:135)
at android.app.ActivityThread.main(ActivityThread.java:5312)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:901)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:696)
我已经尝试了我能想到的一切。 我正在轮询GPS,以便为操作系统提供准确的位置,以提高地理围栏的准确性。我知道它会耗尽我的电池但是现在这不是问题。
答案 0 :(得分:0)
Service
已有Context
。您不应该使用Context
中的Activity
,因为如果您的Activity
被杀mActivity
将导致所有类型的问题。用{/ p>替换createRequestPendingIntent
中的else块
} else {
Intent intent = new Intent("com.example.android.geofence.ACTION_RECEIVE_GEOFENCE");
return PendingIntent.getBroadcast(
this,
0,
intent,
PendingIntent.FLAG_UPDATE_CURRENT);
}