سؤال

I have a fragment with a listview in it, that retrieves the users location, then updates the list view based on the users location.

The problem with my code, is that it seems to grab the location update the list, then keep updating. And reloading the list, almost to the point of annoyance. Here is my code:

public class FindBrewery extends Fragment implements LocationListener {

    private TextView latituteField;
    private TextView longitudeField;
    LocationManager locationManager;
    private String provider;


    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);
        Context c = getActivity().getApplicationContext();
        locationManager =(LocationManager)activity.getSystemService(Context.LOCATION_SERVICE);

    }



    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

    }

    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        //todo change view
        View rootView = inflater.inflate(R.layout.beer_location_list,container, false);

        // Get the location manager
        // Define the criteria how to select the locatioin provider -> use
        // default
        Criteria criteria = new Criteria();
        provider = locationManager.getBestProvider(criteria, false);
        Location location = locationManager.getLastKnownLocation(provider);

        // Initialize the location fields
        if (location != null) {
            System.out.println("Provider " + provider + " has been selected.");
            onLocationChanged(location);
        } else {

        }


        return rootView;
    }




    /* Request updates at startup */
    @Override
    public void onResume() {
        super.onResume();
        locationManager.requestLocationUpdates(provider, 400, 1, this);
    }

    /* Remove the locationlistener updates when Activity is paused */
    @Override
    public void onPause() {
        super.onPause();
        locationManager.removeUpdates(this);
    }

    @Override
    public void onLocationChanged(Location location) {
        int lat = (int) (location.getLatitude());
        int lng = (int) (location.getLongitude());
        //latituteField.setText(String.valueOf(lat));
        //longitudeField.setText(String.valueOf(lng));

        //Toast.makeText(this, "Finding your loaction",Toast.LENGTH_SHORT).show();

        //call asycn task for location
        String url = "myURL";

        Log.d("urlTest", url);

        //async task goes here
        new GetNearbyBreweries(this.getActivity()).execute(url);



    }

    @Override
    public void onStatusChanged(String provider, int status, Bundle extras) {
        // TODO Auto-generated method stub

    }

    @Override
    public void onProviderEnabled(String provider) {
        //Toast.makeText(this, "Enabled new provider " + provider,Toast.LENGTH_SHORT).show();

    }

    @Override
    public void onProviderDisabled(String provider) {
        //Toast.makeText(this, "Disabled provider " + provider,Toast.LENGTH_SHORT).show();
    }



}
هل كانت مفيدة؟

المحلول

Maybe you'd want to try this approach:

LocationClient mLocationClient;
LocationRequest mLocationRequest;

@Override
public void onAttach(Activity activity) {
  if (GooglePlayServicesUtil.isGooglePlayServicesAvailable(activity)) {
    mLocationClient = new LocationClient(activity, activity, activity);

    mLocationRequest = LocationRequest.create();
    mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
    mLocationRequest.setInterval(5000);
    mLocationRequest.setNumUpdates(1);
    mLocationRequest.setFastestInterval(1000);
  }
}

@Override
public void onActivityCreated(Bundle savedInstanceState) {
  if (mLocationClient != null) {
    mLocationClient.connect();
  }
}

@Override
protected void onStop() {
  if (mLocationClient != null) {
    if (mLocationClient.isConnected()) {
      mLocationClient.removeLocationUpdates(this);
    }

    mLocationClient.disconnect();
  }
  super.onStop();
}

@Override
public void onConnected(Bundle dataBundle) {
  LocationManager lm = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
  mLocationClient.requestLocationUpdates(mLocationRequest, this);
}

@Override
public void onLocationChanged(Location location) {
  int lat = (int) (location.getLatitude());
  int lng = (int) (location.getLongitude());

  // post to a handler to update the list items
}

The trick is in the following:

  • you don't use getLastKnownLocation as it uses cache and more often than not returns wrong data,
  • you set setNumUpdates(1) so you don't need to call removeLocationUpdates()

Don't forget AndroidManifest permissions:

<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

نصائح أخرى

Here is a huge post on GPS location and how to check it every so often. (30 minutes in that example)

You also may want to have a look at Timer to set a repeated call to a method that gets the location at the interval you want.

Though it may be a bit robust for your needs, check out Fused Location Provider. It is pretty revolutionary as far as the Location Manager in Android goes. It allows you to do certain things like setting the maximum and minimum interval times as well as a pretty straight forward shut down implementation. I did my first run through from this example and it worked really well (I was trying to do the opposite, I needed updates every 5 seconds where Android was doing updates ever 30-45 seconds):

http://www.kpbird.com/2013/06/fused-location-provider-example.html

You should remove updates from the gps somewhere in your code (suppose that in your case you might do it when you have the current localtion from the user), so call locationManager.removeUpdates(this); inside the onLocationChanged() method once you have a suitable location for your needs.

I've used a separate service for this purpose and implemented GPS relates features inside of it. This service makes location requests and broadcasts them back. So you can just register receiver to obtain received coordinates.

LocationService.java

package com.my.package.services;

import android.app.Service;
import android.content.Intent;
import android.location.Location;
import android.os.Bundle;
import android.os.IBinder;
import android.util.Log;

import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GooglePlayServicesClient.ConnectionCallbacks;
import com.google.android.gms.common.GooglePlayServicesClient.OnConnectionFailedListener;
import com.google.android.gms.location.LocationClient;
import com.google.android.gms.location.LocationListener;
import com.google.android.gms.location.LocationRequest;


public class LocationService extends Service implements LocationListener, ConnectionCallbacks, OnConnectionFailedListener {
    private static final String TAG = LocationService.class.getSimpleName();

    public static final String BROADCAST_ACTION = "com.my.package.LOCATION_UPDATE";

    // Milliseconds per second
    private static final int MILLISECONDS_PER_SECOND = 1000;

    // Update frequency in seconds
    public static final int UPDATE_INTERVAL_IN_SECONDS = 60;

    // Update frequency in milliseconds
    private 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 = 40;

    // A fast frequency ceiling in milliseconds
    private static final long FASTEST_INTERVAL = MILLISECONDS_PER_SECOND * FASTEST_INTERVAL_IN_SECONDS;

    private LocationClient locationClient;

    @Override
    public void onCreate() {
        super.onCreate();

        Log.d(TAG, "Location service created…");

        locationClient = new LocationClient(this, this, this);
        locationClient.connect();
    }

    // Unregister location listeners
    private void clearLocationData() {
        locationClient.disconnect();

        if (locationClient.isConnected()) {
            locationClient.removeLocationUpdates(this);
        }
    }

    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }


    // When service destroyed we need to unbind location listeners
    @Override
    public void onDestroy() {
        super.onDestroy();

        Log.d(TAG, "Location service destroyed…");

        clearLocationData();
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.d(TAG, "Calling command…");

        return START_STICKY;
    }

    @Override
    public void onConnected(Bundle bundle) {
        Log.d(TAG, "Location Callback. onConnected");

        Location currentLocation = locationClient.getLastLocation();

        // Create the LocationRequest object
        LocationRequest locationRequest = LocationRequest.create();

        // Use power balanced mode
        locationRequest.setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY);

        // Set the update interval to 5 seconds
        locationRequest.setInterval(UPDATE_INTERVAL);

        // Set the fastest update interval to 1 second
        locationRequest.setFastestInterval(FASTEST_INTERVAL);

        locationClient.requestLocationUpdates(locationRequest, this);

        onLocationChanged(currentLocation);
    }

    @Override
    public void onLocationChanged(Location location) {
        Log.d(TAG, "onLocationChanged");
        Log.d(TAG, "LOCATION: " + location.getLatitude() + ":" + location.getLongitude());

        // Since location information updated, broadcast it
        Intent broadcast = new Intent();

        // Set action so other parts of application can distinguish and use this information if needed
        broadcast.setAction(BROADCAST_ACTION);
        broadcast.putExtra("latitude", location.getLatitude());
        broadcast.putExtra("longitude", location.getLongitude());

        sendBroadcast(broadcast);
    }

    @Override
    public void onDisconnected() {
        Log.d(TAG, "Location Callback. onDisconnected");
    }

    @Override
    public void onConnectionFailed(ConnectionResult connectionResult) {
        Log.d(TAG, "Location Callback. onConnectionFailed");
    }
}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top