正在处理需要经常更新位置的应用,即使它在后台也是如此。在文档here之后,我正在使用挂起的intent而不是locationlistener。我的代码在
之下/**
* Created by philip on 7/30/16.
*/
public class LocationService extends Service implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener{
private GoogleApiClient mGoogleApiClient;
private LocationRequest mLocationRequest;
public static final long UPDATE_INTERVAL_IN_MILLISECONDS = 1000 * 30; //1 minute;
/**
* The fastest rate for active location updates. Exact. Updates will never be more frequent
* than this value.
*/
public static final long FASTEST_UPDATE_INTERVAL_IN_MILLISECONDS =
UPDATE_INTERVAL_IN_MILLISECONDS / 2;
private String mLastUpdateTime;
private Location mCurrentLocation;
private GeoFire mGeoFire = null;
private String uuid = null;
private Intent intentService;
private PendingIntent mPendingIntent;
@Override
public void onCreate() {
super.onCreate();
Firebase.setAndroidContext(this);
buildGoogleApiClient();
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (!mGoogleApiClient.isConnected()) {
mGoogleApiClient.connect();
}
createLocationRequest();
if(intent != null){
intentService = new Intent(this, LocationBroadcastReceiver.class);
intentService.putExtra("UUID", intent.getStringExtra("UUID"));
intentService.setAction("foo.LOCATION_UPDATE_INTENT");
mPendingIntent = PendingIntent.getBroadcast(this, 0, intentService, PendingIntent.FLAG_UPDATE_CURRENT);
}
return START_REDELIVER_INTENT;
}
/********************************************** Google api connection callback below **************************************/
/***
* callback fired once connection has been established
* @param bundle
*/
@Override
public void onConnected(Bundle bundle) {
startLocationUpdates();
Log.i(this.getClass().getSimpleName(), "Location Service api has been connected");
}
/***
* callback fired when connection fails
* @param connectionResult
*/
@Override
public void onConnectionFailed(@NonNull ConnectionResult connectionResult) {
Log.i(this.getClass().getSimpleName(), "Location Service disconnected");
}
/**
* callback fired when connection is temporary suspended
* @param i
*/
@Override
public void onConnectionSuspended(int i) {
if (mGoogleApiClient != null) {
mGoogleApiClient.connect();
}
}
/************************************** Ease methods ************************************************/
/**
* Builds a GoogleApiClient. Uses the {@code #addApi} method to request the
* LocationServices API.
*/
protected synchronized void buildGoogleApiClient() {
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(API)
.build();
}
/**
* Requests location updates from the FusedLocationApi.
*/
protected void startLocationUpdates() {
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
// TODO: Consider calling
return;
}
FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, mPendingIntent);
}
protected void createLocationRequest() {
mLocationRequest = new LocationRequest();
// Sets the desired interval for active location updates. This interval is
// inexact. You may not receive updates at all if no location sources are available, or
// you may receive them slower than requested. You may also receive updates faster than
// requested if other applications are requesting location at a faster interval.
mLocationRequest.setInterval(UPDATE_INTERVAL_IN_MILLISECONDS);
// Sets the fastest rate for active location updates. This interval is exact, and your
// application will never receive updates faster than this value.
mLocationRequest.setFastestInterval(FASTEST_UPDATE_INTERVAL_IN_MILLISECONDS);
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
}
}
和我的广播接收者
@Override
public void onReceive(Context context, Intent intent) {
Firebase.setAndroidContext(context);
Log.i(getClass().getSimpleName(), "broadcast has been called");
if (intent != null) {
String uuid = intent.getStringExtra("UUID");
mGeoFire = new GeoFire(new Firebase("https://foo.firebaseio.com/users/" + uuid));
LocationResult locationResult = LocationResult.extractResult(intent);
if(locationResult == null){// check for null pointer
Log.i(getClass().getSimpleName(), "location result is null <<<<<<<<<<<<<<<<<<");
return;
}
Log.i(getClass().getSimpleName(), "location result found >>>>>>>>>>>>>>>>>>>>====>>>>>>>>>>>>>>>>>>>");
location = locationResult.getLastLocation();
}
if( isBetterLocation(location, currentBestLocation)){
currentBestLocation = location;
}else {
return;
}
if (mGeoFire != null) {
mGeoFire.setLocation("location", new GeoLocation(location.getLatitude(), location.getLongitude()));
}
}
我面临的问题是
LocationResult locationResult = LocationResult.extractResult(intent);
会返回null
这是我听到广播收藏家的最后一次
答案 0 :(得分:1)
我基本上将听众移至onConnected
并检查了null
。那之后它运作良好。
package com.github.robophil.location_service;
import android.Manifest;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.location.Location;
import android.os.Bundle;
import android.os.IBinder;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.ActivityCompat;
import android.util.Log;
import android.widget.Toast;
import com.firebase.client.Firebase;
import com.firebase.geofire.GeoFire;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.location.LocationRequest;
import com.google.android.gms.location.LocationResult;
import static com.google.android.gms.location.LocationServices.API;
import static com.google.android.gms.location.LocationServices.FusedLocationApi;
/**
* Created by philip on 7/30/16.
*/
public class LocationService extends Service implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener {
private GoogleApiClient mGoogleApiClient;
private LocationRequest mLocationRequest;
public static final String prefName = "com.github.robophil.pref";
public static final long UPDATE_INTERVAL_IN_MILLISECONDS = 1000 * 60; //1 minute;
/**
* The fastest rate for active location updates. Exact. Updates will never be more frequent
* than this value.
*/
public static final long FASTEST_UPDATE_INTERVAL_IN_MILLISECONDS =
UPDATE_INTERVAL_IN_MILLISECONDS / 2;
private String mLastUpdateTime;
private Location mCurrentLocation;
private GeoFire mGeoFire = null;
private String uuid = null;
private Intent intentService;
private PendingIntent mPendingIntent;
@Override
public void onCreate() {
super.onCreate();
Firebase.setAndroidContext(this);
buildGoogleApiClient();
}
@Override
public void onDestroy() {
if(mGoogleApiClient != null){
if(mGoogleApiClient.isConnected()){
mGoogleApiClient.disconnect();
FusedLocationApi.removeLocationUpdates(mGoogleApiClient, mPendingIntent);
}
}
super.onDestroy();
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (intent != null) {
if(!intent.hasExtra("UUID") || !intent.hasExtra("URL")){
Log.i(getClass().getSimpleName(), "Service has stopped itself");
Toast.makeText(this, "stopself called", Toast.LENGTH_SHORT).show();
stopSelf();
}
SharedPreferences.Editor editor = getSharedPreferences(LocationService.prefName, getApplicationContext().MODE_PRIVATE).edit();
editor.putString("UUID", intent.getStringExtra("UUID"));
editor.putString("URL", intent.getStringExtra("URL"));
editor.apply();
intentService = new Intent(this, LocationIntentService.class);
intentService.setExtrasClassLoader(LocationResult.class.getClassLoader());
mPendingIntent = PendingIntent.getService(getApplicationContext(), 0, intentService, PendingIntent.FLAG_UPDATE_CURRENT);
}
if (!mGoogleApiClient.isConnected()) {
mGoogleApiClient.connect();
}
return START_REDELIVER_INTENT;
}
/********************************************** Google api connection callback below **************************************/
/***
* callback fired once connection has been established
* @param bundle
*/
@Override
public void onConnected(Bundle bundle) {
createLocationRequest();
startLocationUpdates();
Log.i(this.getClass().getSimpleName(), "Location Service api has been connected");
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
// TODO: Consider calling
return;
}
Location location = FusedLocationApi.getLastLocation(mGoogleApiClient);
if (location == null){
Log.i(getClass().getSimpleName(), "init location is null");
return;
}
Log.i(getClass().getSimpleName(), "init location ==> "+location.getAccuracy()+" "+location.getProvider());
}
/***
* callback fired when connection fails
* @param connectionResult
*/
@Override
public void onConnectionFailed(@NonNull ConnectionResult connectionResult) {
Log.i(this.getClass().getSimpleName(), "Location Service disconnected");
}
/**
* callback fired when connection is temporary suspended
* @param i
*/
@Override
public void onConnectionSuspended(int i) {
if (mGoogleApiClient != null) {
mGoogleApiClient.connect();
}
}
/************************************** Ease methods ************************************************/
/**
* Builds a GoogleApiClient. Uses the {@code #addApi} method to request the
* LocationServices API.
*/
protected synchronized void buildGoogleApiClient() {
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(API)
.build();
}
/**
* Requests location updates from the FusedLocationApi.
*/
protected void startLocationUpdates() {
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
// TODO: Consider calling
return;
}
// FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, this);
FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, mPendingIntent);
}
protected void createLocationRequest() {
mLocationRequest = new LocationRequest();
// Sets the desired interval for active location updates. This interval is
// inexact. You may not receive updates at all if no location sources are available, or
// you may receive them slower than requested. You may also receive updates faster than
// requested if other applications are requesting location at a faster interval.
mLocationRequest.setInterval(UPDATE_INTERVAL_IN_MILLISECONDS);
// Sets the fastest rate for active location updates. This interval is exact, and your
// application will never receive updates faster than this value.
mLocationRequest.setFastestInterval(FASTEST_UPDATE_INTERVAL_IN_MILLISECONDS);
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
}
}
用于我的待定意图的LocationsIntentService保持不变,只是在执行任何操作之前检查null
package com.github.robophil.location_service;
import android.app.IntentService;
import android.content.Intent;
import android.content.SharedPreferences;
import android.location.Location;
import android.os.Bundle;
import android.util.Log;
import com.firebase.client.Firebase;
import com.firebase.geofire.GeoFire;
import com.firebase.geofire.GeoLocation;
import com.google.android.gms.location.LocationResult;
import java.util.Set;
/**
* Created by philip on 8/7/16.
*/
public class LocationIntentService extends IntentService {
private GeoFire mGeoFire;
private Location location, currentBestLocation;
/**
* Creates an IntentService. Invoked by your subclass's constructor.
*
* @param name Used to name the worker thread, important only for debugging.
*/
public LocationIntentService(String name) {
super("i am a value");
}
public LocationIntentService(){
super("i am a value");
}
@Override
protected void onHandleIntent(Intent intent) {
Firebase.setAndroidContext(this);
Log.i(getClass().getSimpleName(), "intent service has been called");
SharedPreferences pref = getSharedPreferences(LocationService.prefName, getApplicationContext().MODE_PRIVATE);
String uuid = pref.getString("UUID", null);
String url = pref.getString("URL", null);
if(uuid == null || url==null){
stopSelf();
return;
}
if (intent != null) {
mGeoFire = new GeoFire(new Firebase(url +"/"+ uuid));
Log.i(getClass().getSimpleName(), "user id found ==> "+uuid+", "+url);
Bundle extra = intent.getExtras();
Set<String> extraKeySet = extra.keySet();
for(String key: extraKeySet){
Log.i(getClass().getSimpleName(), "key found ==> "+ key);
}
if(LocationResult.hasResult(intent)){
Log.i(getClass().getSimpleName(), "intent contains location");
}
LocationResult locationResult = LocationResult.extractResult(intent);
if(locationResult == null){// check for null pointer
Log.i(getClass().getSimpleName(), "location result is null ...");
return;
}
Log.i(getClass().getSimpleName(), "location result found");
location = locationResult.getLastLocation();
}
if( isBetterLocation(location, currentBestLocation)){
currentBestLocation = location;
}else {
return;
}
if (mGeoFire != null) {
mGeoFire.setLocation("location", new GeoLocation(location.getLatitude(), location.getLongitude()));
}
}
private static final int TWO_MINUTES = 1000 * 60 * 2;
/** Determines whether one Location reading is better than the current Location fix
* @param location The new Location that you want to evaluate
* @param currentBestLocation The current Location fix, to which you want to compare the new one
*/
protected boolean isBetterLocation(Location location, Location currentBestLocation) {
if (currentBestLocation == null) {
// A new location is always better than no location
return true;
}
// Check whether the new location fix is newer or older
long timeDelta = location.getTime() - currentBestLocation.getTime();
boolean isSignificantlyNewer = timeDelta > TWO_MINUTES;
boolean isSignificantlyOlder = timeDelta < -TWO_MINUTES;
boolean isNewer = timeDelta > 0;
// If it's been more than two minutes since the current location, use the new location
// because the user has likely moved
if (isSignificantlyNewer) {
return true;
// If the new location is more than two minutes older, it must be worse
} else if (isSignificantlyOlder) {
return false;
}
// Check whether the new location fix is more or less accurate
int accuracyDelta = (int) (location.getAccuracy() - currentBestLocation.getAccuracy());
boolean isLessAccurate = accuracyDelta > 0;
boolean isMoreAccurate = accuracyDelta < 0;
boolean isSignificantlyLessAccurate = accuracyDelta > 200;
// Check if the old and new location are from the same provider
boolean isFromSameProvider = isSameProvider(location.getProvider(),
currentBestLocation.getProvider());
// Determine location quality using a combination of timeliness and accuracy
if (isMoreAccurate) {
return true;
} else if (isNewer && !isLessAccurate) {
return true;
} else if (isNewer && !isSignificantlyLessAccurate && isFromSameProvider) {
return true;
}
return false;
}
/** Checks whether two providers are the same */
private boolean isSameProvider(String provider1, String provider2) {
if (provider1 == null) {
return provider2 == null;
}
return provider1.equals(provider2);
}
}