Play Location Services getLastLocation returns null

前端 未结 8 1757
感动是毒
感动是毒 2021-01-13 13:51

I am trying to listen to location changes but sometimes onLocationChanged callback is never called and getLastLocation returns null, w

相关标签:
8条回答
  • 2021-01-13 13:57

    This problem can appear if google maps hasn't determined location of your device yet. Try launching Google Maps. If it can not then fix this issue in device's settings (say by enabling WLAN + GPS).

    0 讨论(0)
  • 2021-01-13 13:57

    The google maps must be working because it must be caching the previous location info or directly using location api-not the google play services location api..

    0 讨论(0)
  • 2021-01-13 14:04

    I have developed my application based on below code you can use if you want My application name is "https://play.google.com/store/apps/details?id=com.deep.profilemaper" .

    Here is my code : BackgroundLocationService.java

    public class BackgroundLocationService extends Service implements
        GooglePlayServicesClient.ConnectionCallbacks,GooglePlayServicesClient.OnConnectionFailedListener,LocationListener  {
    
        IBinder mBinder = new LocalBinder();
    
        private LocationClient mLocationClient;
        private LocationRequest mLocationRequest;
       // Flag that indicates if a request is underway.
       private boolean mInProgress;
    
       private Boolean servicesAvailable = false;
    
    public class LocalBinder extends Binder {
        public BackgroundLocationService getServerInstance() {
            return BackgroundLocationService.this;
        }
    }
    
    @Override
    public void onCreate() {
        super.onCreate();
    
    
        mInProgress = false;
        // Create the LocationRequest object
        mLocationRequest = LocationRequest.create();
        // Use high accuracy
        mLocationRequest.setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY);
        // Set the update interval to 5 seconds
        mLocationRequest.setInterval(Constants.UPDATE_INTERVAL);
        // Set the fastest update interval to 1 second
        mLocationRequest.setFastestInterval(Constants.FASTEST_INTERVAL);
    
        servicesAvailable = servicesConnected();
    
        /*
         * Create a new location client, using the enclosing class to
         * handle callbacks.
         */
        mLocationClient = new LocationClient(this, this, this);
    
    
    }
    
    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) {
    
            return true;
        } else {
    
            return false;
        }
    }
    
    public int onStartCommand (Intent intent, int flags, int startId)
    {
        super.onStartCommand(intent, flags, startId);
    
        if(!servicesAvailable || mLocationClient.isConnected() || mInProgress)
            return START_STICKY;
    
        setUpLocationClientIfNeeded();
        if(!mLocationClient.isConnected() || !mLocationClient.isConnecting() && !mInProgress)
        {
            appendLog(DateFormat.getDateTimeInstance().format(new Date()) + ": Started", Constants.LOG_FILE);
            mInProgress = true;
            mLocationClient.connect();
        }
    
        return START_STICKY;
    }
    
    /*
     * Create a new location client, using the enclosing class to
     * handle callbacks.
     */
    private void setUpLocationClientIfNeeded()
    {
        if(mLocationClient == null) 
            mLocationClient = new LocationClient(this, this, this);
    }
    
    // Define the callback method that receives location updates
    @Override
    public void onLocationChanged(Location location) {
        // Report to the UI that the location was updated
        String msg = Double.toString(location.getLatitude()) + "," +
                Double.toString(location.getLongitude());
        Log.d("debug", msg);
        // Toast.makeText(this, msg, Toast.LENGTH_SHORT).show();
        appendLog(msg, Constants.LOCATION_FILE);
    }
    
    @Override
    public IBinder onBind(Intent intent) {
        return mBinder;
    }
    
    public String getTime() {
        SimpleDateFormat mDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        return mDateFormat.format(new Date());
    }
    
    public void appendLog(String text, String filename)
    {       
       File logFile = new File(filename);
       if (!logFile.exists())
       {
          try
          {
             logFile.createNewFile();
          } 
          catch (IOException e)
          {
             // TODO Auto-generated catch block
             e.printStackTrace();
          }
       }
       try
       {
          //BufferedWriter for performance, true to set append to file flag
          BufferedWriter buf = new BufferedWriter(new FileWriter(logFile, true)); 
          buf.append(text);
          buf.newLine();
          buf.close();
       }
       catch (IOException e)
       {
          // TODO Auto-generated catch block
          e.printStackTrace();
       }
    }
    
    @Override
    public void onDestroy(){
        // Turn off the request flag
        mInProgress = false;
        if(servicesAvailable && mLocationClient != null) {
            mLocationClient.removeLocationUpdates(this);
            // Destroy the current location client
            mLocationClient = null;
        }
        // Display the connection status
        // Toast.makeText(this, DateFormat.getDateTimeInstance().format(new Date()) + ": Disconnected. Please re-connect.", Toast.LENGTH_SHORT).show();
        appendLog(DateFormat.getDateTimeInstance().format(new Date()) + ": Stopped", Constants.LOG_FILE);
        super.onDestroy();  
    }
    
    /*
     * Called by Location Services when the request to connect the
     * client finishes successfully. At this point, you can
     * request the current location or start periodic updates
     */
    @Override
    public void onConnected(Bundle bundle) {
    
        // Request location updates using static settings
        mLocationClient.requestLocationUpdates(mLocationRequest, this);
        appendLog(DateFormat.getDateTimeInstance().format(new Date()) + ": Connected", Constants.LOG_FILE);
    
    }
    
    /*
     * Called by Location Services if the connection to the
     * location client drops because of an error.
     */
    @Override
    public void onDisconnected() {
        // Turn off the request flag
        mInProgress = false;
        // Destroy the current location client
        mLocationClient = null;
        // Display the connection status
        // Toast.makeText(this, DateFormat.getDateTimeInstance().format(new Date()) + ": Disconnected. Please re-connect.", Toast.LENGTH_SHORT).show();
        appendLog(DateFormat.getDateTimeInstance().format(new Date()) + ": Disconnected", Constants.LOG_FILE);
    }
    
    /*
     * Called by Location Services if the attempt to
     * Location Services fails.
     */
    @Override
    public void onConnectionFailed(ConnectionResult connectionResult) {
        mInProgress = false;
    
        /*
         * 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()) {
    
        // If no resolution is available, display an error dialog
        } else {
    
          }
        }
    
    }
    

    ***Constants.java***

    public final class Constants {
    
    // Milliseconds per second
    private static final int MILLISECONDS_PER_SECOND = 1000;
    // Update frequency in seconds
    private static final int UPDATE_INTERVAL_IN_SECONDS = 30;
    // Update frequency in milliseconds
    public static final long UPDATE_INTERVAL = MILLISECONDS_PER_SECOND * UPDATE_INTERVAL_IN_SECONDS;
    // The fastest update frequency, in seconds
    private static final int FASTEST_INTERVAL_IN_SECONDS = 30;
    // A fast frequency ceiling in milliseconds
    public static final long FASTEST_INTERVAL = MILLISECONDS_PER_SECOND * FASTEST_INTERVAL_IN_SECONDS;
    // Stores the lat / long pairs in a text file
    public static final String LOCATION_FILE = "sdcard/location.txt";
    // Stores the connect / disconnect data in a text file
    public static final String LOG_FILE = "sdcard/log.txt";
    
    
    /**
     * Suppress default constructor for noninstantiability
     */
    private Constants() {
        throw new AssertionError();
        }
    }
    

    This code contains some variables like current Date and Time and constants like LOG_File that is only for logging purpose . so, i have excluded that code . This code is perfectly tested and working . Give it a try.

    Thanks.

    0 讨论(0)
  • 2021-01-13 14:04

    You are using getLastLocation() for a purpose other than what it was intended. getLastLocation() is used when a location aware app is 1st starting. After two days you should have a very accurate fix. Why haven't you followed the location aware design guides.

    I'd say you need to return START_STICKY. But you have coded onStartCommand() and onBind(). You'd also need to start the service then bind to it for the START_STICKY to work after clients have unbound.

    Don't check for GooglePlay in the service. The service needs to be light weight check for GooglePlay in an activity before starting the service. The lighter a service is the more chance it will stay in memory. Run the Service in a separate process.

    0 讨论(0)
  • 2021-01-13 14:05

    Its possible that your service is just being killed, it can happen. Try changing the value returned from your onStartCommand() to

    return STICKY_START;
    

    This will restart the service as soon as resources are available.

    Here is the relevant section in the API Reference

    public static final int START_STICKY

    Added in API level 5 Constant to return from onStartCommand(Intent, int, int): if this service's process is killed while it is started (after returning from onStartCommand(Intent, int, int)), then leave it in the started state but don't retain this delivered intent. Later the system will try to re-create the service. Because it is in the started state, it will guarantee to call onStartCommand(Intent, int, int) after creating the new service instance; if there are not any pending start commands to be delivered to the service, it will be called with a null intent object, so you must take care to check for this.

    This mode makes sense for things that will be explicitly started and stopped to run for arbitrary periods of time, such as a service performing background music playback.

    Constant Value: 1 (0x00000001)

    0 讨论(0)
  • 2021-01-13 14:06

    Firstly it is a bug. I also faced this problem.

    You can try a simple workaround.

    Do a request for location update before you try to get last location, i.e. Request for location updates before you try to find the last location using getLastLocation();

    Just like:

    LocationManager locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
    Criteria crta = new Criteria();
    crta.setAccuracy(Criteria.ACCURACY_FINE);
    crta.setAltitudeRequired(true);
    crta.setBearingRequired(true);
    crta.setCostAllowed(true);
    crta.setPowerRequirement(Criteria.POWER_LOW); 
    String provider = locationManager.getBestProvider(crta, true);
    Log.d("","provider : "+provider);
    // String provider = LocationManager.GPS_PROVIDER; 
    locationManager.requestLocationUpdates(provider, 1000, 0, locationListener);
    Location location = locationManager.getLastKnownLocation(provider); 
    

    This implementation is based of LocationManager. Please opt Location Client for same.

    Hope it helps!

    UPDATE

    Here you can also go for onLocationChanged() method as it will update you each time location is changed while getLastLocation() method returns best known location which might be NULL.

    As per doc, GetLastLocation() method will return NULL in very rare cases. But this happens often with me too.

    NEWEST UPDATE

    Guys only one update regarding GPS :

    Firstly we need to make use of GoogleApiClient instead LocationClient class.

    Secondly we need to implement GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener

    Third we need to override its onConnected() , onConnectionSuspended() and onConnectionFailed() method.

    Rest you are good to go.

    CHEERS!

    0 讨论(0)
提交回复
热议问题