3

Ich mache eine Android-Anwendung, in der ein Geofence bei LatLong Koordinaten auf meinem Server angegeben erstellen möchten.Erstellen von Geofences im Hintergrund Service

Die Koordinaten werden regelmäßig im Hintergrund von einem Dienst aktualisiert. Ich lese diese Koordinaten und möchte im Hintergrund einen Geofence ohne Benutzereingriff erstellen. Ich habe es in einem Dienst versucht, aber es funktioniert nicht. Ich kann die Koordinaten vom Server in regelmäßigen Abständen abrufen, aber ich kann nicht Geofence dafür erstellen, eine NullPointerException zu erhalten.

Allerdings kann ich Geofences in einer Aktivität auf einen Knopfdruck (Hardcoding LatLong Koordinaten) erstellen, aber es funktioniert nicht in einem Dienst.

Mein Service:

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); 
    } 
} 

}

Meine Protokolle:

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) 

Ich habe versucht, alles, was ich denken konnte. Ich lese das GPS ab, um dem OS eine genaue Position zu geben, um die Genauigkeit des Geofencing zu erhöhen. Ich weiß, dass es meine Batterie entleert, aber für jetzt ist das kein Problem.

Antwort

0

Service hat bereits Context. Sie sollten Context nicht von Activity verwenden, denn wenn Activity getötet wird, wird mActivity null sein und alle Arten von Problemen verursachen. Ersetzen Sie sonst Block in createRequestPendingIntent mit diesem

} else { 
    Intent intent = new Intent("com.example.android.geofence.ACTION_RECEIVE_GEOFENCE"); 
    return PendingIntent.getBroadcast(
      this, 
      0, 
      intent, 
      PendingIntent.FLAG_UPDATE_CURRENT); 
}