添加链接
link之家
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接
Collectives™ on Stack Overflow

Find centralized, trusted content and collaborate around the technologies you use most.

Learn more about Collectives

Teams

Q&A for work

Connect and share knowledge within a single location that is structured and easy to search.

Learn more about Teams

I am developing an application which lists restaurants closest to the user. When the refresh button is clicked, it lists the restaurants for the user's current location. I am using the Location Manager and requesting updates only when the activity comes to foreground(onResume) to avoid the constant usage of the battery. When the app goes in onPause(), the location updates are stopped. It works fine on the emulator when I pass the updates through the terminal.

Problem: When I physically change my location (say drive 5 miles away) and I open my app and the activity to show the nearest restaurants, it takes long time(4-5 minutes) for the location to refresh and till then the app continues to show the restaurants for the previous location. But if I physically change my location and access Google Maps and then open my restaurant application, then it works instantaneously. I have ensured that the GPS is switched on. What can I do to get the Location Manager to kick in and refresh the location as soon as I open my activity? Thank you in advance!

package com.mortley.android.restaurantsaver;
public class NearbyRestaurantActivity extends ListActivity implements OnClickListener, LocationListener{
    private Button refreshButton, searchRestaurants; 
    ImageButton goToSearch;
    private double[] lastKnownLocation;
    private EditText locationEditText;
    private LocationManager locManager;
    private LocationListener locListener;
    private boolean gps_enabled = false;
    private boolean network_enabled = false;
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.nearbyrestaurants);
        refreshButton = (Button)findViewById(R.id.reloadButton);
        refreshButton.setOnClickListener(this);
        searchRestaurants = (Button)findViewById(R.id.searchButton);
        searchRestaurants.setOnClickListener(this);
        goToSearch = (ImageButton)findViewById(R.id.goLocationButton);
        goToSearch.setOnClickListener(this);
        locationEditText = (EditText)findViewById(R.id.addressTextBox);
        locationEditText.setVisibility(View.GONE);
        goToSearch.setVisibility(View.GONE);
        locManager = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE);//??
        locManager.requestLocationUpdates( LocationManager.GPS_PROVIDER, 1000, 100, this);
        //checks network connectivity
        boolean checkConnection = isNetworkAvailable();
        if(!checkConnection){
            Toast.makeText(getApplicationContext(), "Check your Network Connectivity", Toast.LENGTH_LONG).show();
        if(checkConnection){
            //sets current location parameters for the user
            lastKnownLocation = RestaurantHelper.getLastKnownLocation(this);
            //Log.v("NearbyRestaurantActivity", "This"+this);
            RestaurantApplication application = (RestaurantApplication) this.getApplication();
            RestaurantAdapter restaurantAdapter = new RestaurantAdapter(this, R.layout.restaurantrow,  R.id.label,new ArrayList<RestaurantReference>());
            restaurantAdapter.setLastKnownLocation(lastKnownLocation);  
            //set a global variable for the RestaurantAdapter in the RestaurantApplication class.
            application.setRestaurantAdapter(restaurantAdapter);
            //Set the adapter first and then update it when the RestaurantHttpAsyncTask makes a web service call.
            setListAdapter(restaurantAdapter);
            //Make a webservice call in a different thread passing Keyword for URL as a string array.
            RestaurantHttpAsyncTask m_progressTask;
            String[] keywords = {"", "american", "asian", "italian","mexican"};
            //String[] keywords = {"indian"};
            m_progressTask = new RestaurantHttpAsyncTask(NearbyRestaurantActivity.this, keywords);
            m_progressTask.setRestaurantAdapter(restaurantAdapter);
            m_progressTask.execute();
    @Override
    public void onClick(View v) {   
        //Refresh button helps to refresh the restaurant list on location change. Again it makes a call to the webservice using Async Task
        if(v.getId() == refreshButton.getId() ){
            try {
                gps_enabled = locManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
            } catch (Exception ex) {
                ex.printStackTrace();
            try {
                network_enabled = locManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
            } catch (Exception ex) {
                ex.printStackTrace();
            // don't start listeners if no provider is enabled
            if (!gps_enabled && !network_enabled) {
                Toast.makeText(getApplicationContext(), "Sorry, Location is not determined. Please enable your Network Providers.", Toast.LENGTH_LONG).show();
            //check network connectivity before refresh
            boolean checkConnection = isNetworkAvailable();
            if(!checkConnection){
                Toast.makeText(getApplicationContext(), "Check your Network Connectivity", Toast.LENGTH_LONG).show();
            if(checkConnection){
                RestaurantApplication application = (RestaurantApplication) this.getApplication();
                RestaurantAdapter restaurantAdapter = new RestaurantAdapter(this, R.layout.restaurantrow,  R.id.label, new ArrayList<RestaurantReference>());
                restaurantAdapter.setLastKnownLocation(lastKnownLocation);  
                //set a global variable for the RestaurantAdapter in the RestaurantApplication class.
                application.setRestaurantAdapter(restaurantAdapter);
                //Set the adapter first and then update it when the RestaurantHttpAsyncTask makes a web service call.
                setListAdapter(restaurantAdapter);
                //Make a webservice call in a different thread passing Keyword for URL as a string array.
                RestaurantHttpAsyncTask m_progressTask, m_progressTask1;
                String[] keywords = {"", "american", "asian", "italian","mexican", "chinese", "indian"};
                //String[] keywords = {"Chinese"};
                m_progressTask = new RestaurantHttpAsyncTask(NearbyRestaurantActivity.this, keywords);
                m_progressTask.setRestaurantAdapter(restaurantAdapter);
                m_progressTask.execute();
        if(v.getId() == goToSearch.getId() ){
            Activity child = this;
            while(child.getParent() != null){
                child = child.getParent();
            TabGroup1Activity parent = (TabGroup1Activity)getParent();
            InputMethodManager imm = (InputMethodManager)getSystemService(
                    Context.INPUT_METHOD_SERVICE);
            imm.hideSoftInputFromWindow(locationEditText.getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);
            //changes ** restaurantAdapter to RestaurantAdapter1 to test & application to application1  
            RestaurantApplication application1 = (RestaurantApplication) this.getApplication();
            RestaurantAdapter restaurantAdapter1 = new RestaurantAdapter(this, R.layout.restaurantrow,  R.id.label, new ArrayList<RestaurantReference>());
            restaurantAdapter1.setLastKnownLocation(lastKnownLocation);  
            //set a global variable for the RestaurantAdapter in the RestaurantApplication class.
            application1.setRestaurantAdapter(restaurantAdapter1);
            //Set the adapter first and then update it when the RestaurantHttpAsyncTask makes a web service call.
            setListAdapter(restaurantAdapter1);
            //Make a webservice call in a different thread passing Keyword for URL as a string array.
            RestaurantHttpAsyncTaskTextSearch m_progressTask, m_progressTask1;
            String keywords = locationEditText.getText().toString();
            if(keywords.equals("")){
                keywords = "Pizza in Palo Alto";
            keywords = keywords.replaceAll(" ", "%20");
            keywords = keywords.replaceAll(",", "%20");
            m_progressTask = new RestaurantHttpAsyncTaskTextSearch (NearbyRestaurantActivity.this, keywords);
            m_progressTask.setRestaurantAdapter(restaurantAdapter1);
            m_progressTask.execute();
            locationEditText.setVisibility(View.GONE);
            goToSearch.setVisibility(View.GONE);
        if(v.getId() == searchRestaurants.getId() ){
            if(goToSearch.isShown() == true){
                goToSearch.setVisibility(View.GONE);
                locationEditText.setVisibility(View.GONE);
            else if(goToSearch.isShown() == false){
                //check network connectivity before refresh
                boolean checkConnection = isNetworkAvailable();
                if(!checkConnection){
                    Toast.makeText(getApplicationContext(), "Check your Network Connectivity", Toast.LENGTH_LONG).show();
                if(checkConnection){
                    goToSearch.setVisibility(View.VISIBLE);
                    locationEditText.setVisibility(View.VISIBLE);
    //Method to check network connectivity
    public boolean isNetworkAvailable() {
        ConnectivityManager connectivityManager 
        = (ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE);
        NetworkInfo activeNetworkInfo = connectivityManager.getActiveNetworkInfo();
        if (activeNetworkInfo != null && activeNetworkInfo.isConnectedOrConnecting()) {
            //Log.d("network", "Network available:true");
            return true;
        } else {
            //Log.d("network", "Network available:false");
            return false;
    @Override
    protected void onResume() {
        super.onResume();
        locManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 50, 100, this); 
        //Log.v("NearbyRestaurantActivity", "In OnResume()");
    @Override
    protected void onPause() {
        super.onPause();
        locManager.removeUpdates(this); 
        //Log.v("NearbyRestaurantActivity", "In onPause()");
    @Override
    public void onLocationChanged(Location location) {
        // TODO Auto-generated method stub
    @Override
    public void onProviderDisabled(String provider) {
        // TODO Auto-generated method stub
    @Override
    public void onProviderEnabled(String provider) {
        // TODO Auto-generated method stub
    @Override
    public void onStatusChanged(String provider, int status, Bundle extras) {
        // TODO Auto-generated method stub
public class RestaurantHelper {
public static double[] getLastKnownLocation(Activity activity){
    double lat = 0.0;
    double lon = 0.0;
    LocationManager lm = (LocationManager) activity.getSystemService(Context.LOCATION_SERVICE);    
    Location location = lm.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);  
    if(location == null){
        lat = 0.0;
        lon = 0.0;
    else{
        //Log.v("Latitude", Double.toString(location.getLatitude()));
        //Log.v("Longitude", Double.toString(location.getLongitude()));
        lat = location.getLatitude();
        lon = location.getLongitude();
    return new double[]{lat,lon};
                It looks like you're missing some code - what is "RestaurantHelper.getLastKnownLocation(this)" and what does it do?  Also, you have no code in "onLocationChanged()", which is where the updates from locManager.requestLocationUpdates() passes in new Locations.  Finally, you're not showing the OnClickListener code.
– Sean Barbeau
                Jun 16, 2013 at 3:22
                android-developers.blogspot.com/2011/06/… (And review the new stuff, like the fused location provider.)
– Charlie Collins
                Jun 17, 2013 at 3:34
                I don't want the restaurants to update automatically when the location changes. Only the location coordinates need to be updated in the background. Should I be using {Latitude = location.getLatitude(); Longitude = location.getLongitude();} in the onLocationChanged() to update the Location? I thought the requestLocationUpdates() updates cashes the latest location internally and getLastKnownLocation() gives the latest location as per the cashed results.
– Chakra
                Jun 17, 2013 at 3:58

The primary reason why you aren't getting updated location information quickly is that you're relying on the NETWORK_PROVIDER in the RestaurantHelper.getLastKnownLocation() method, but registering a LocationListener for the GPS_PROVIDER in onCreate().

So, this code in RestaurantHelper.getLastKnownLocation():

Location location = lm.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);

...should be changed to:

Location location = lm.getLastKnownLocation(LocationManager.GPS_PROVIDER);

In theory, this should then give you the latest GPS location, which should have been refreshed when you register the listener. Conversely, you could also change to listening to the NETWORK_PROVIDER in onCreate() and leave RestaurantHelper.getLastKnownLocation() as is. It depends on your accuracy requirement - if you want high accuracy locations to return the nearest location to the nearest building level (e.g., 5-30m), you should use the GPS_PROVIDER. But, if you can live with coarser accuracy, the NETWORK_PROVIDER typically returns a new location much faster than GPS, especially if you're indoors, and sometimes this can be fairly accurate if derived from WiFi.

Another approach would be to listen to both GPS_PROVIDER and NETWORK_PROVIDER by registering both via two requestLocationUpdates() lines in onCreate(), and then checking to see most recent timestamp on the Location from lm.getLastKnownLocation(LocationManager.GPS_PROVIDER); and lm.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);, and using the one that was updated more recently.

I would also recommend the following changes to make your code reliable on a large number of Android devices:

  • Specify the requestLocationUpdates() minDistance parameter as 0 when listening for GPS or NETWORK location updates - the minDistance parameter has a history of being unreliable and unpredictable in the way its interpreted by OEMs, until Android 4.1.
  • Switch to the new Fused Location Provider - this should be much more reliable when calling the getLastKnownLocation() method than the Android framework location APIs, and more consistent across different devices. Note that this relies on Google Play Services SDK, which is only available on Android 2.2 and higher.
  • Where is this Fused Location Provider you talk of? The link goes to the Android documentation of "Receiving Location Updates". No mention of any "Fused" provider there. – Nilzor Sep 2, 2014 at 12:02 If you're using Google Play Services location (i.e., either LocationClient, which is now deprecated, or LocationServices), you're using the fused provider. The Fused provider is the only provider available via these implementations. – Sean Barbeau Sep 2, 2014 at 15:56
  • LocationClient video, is the new way of doing location stuff. It has improvements over the LocationManager that can be a pain to manage and develop.

  • If you need to use LocationManager, you must know that requestLocationUpdates is buggy (very buggy). Since all its implementations on custom hardware differ. There is a hack/workaround that works. Before you call requestLocationUpdates, just kick start it with the following

  • Code :

     HomeScreen.getLocationManager().requestLocationUpdates(
        LocationManager.NETWORK_PROVIDER, 0, 0, new LocationListener() {
            @Override
            public void onStatusChanged(String provider, int status, Bundle extras) {
            @Override
            public void onProviderEnabled(String provider) {
            @Override
            public void onProviderDisabled(String provider) {
            @Override
            public void onLocationChanged(final Location location) {
                    This kickstarting thing doesn't help Android Bug 57707 which affects at least the network provider.
    – Johan Walles
                    Jan 22, 2014 at 11:01
    

    requestLocationUpdates is buggy. Use network provider always to trigger onLocationChanged(...)

    locManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 1000, 100, this)
    

    only after using network provider use gps provider back to back:

    locManager.requestLocationUpdates( LocationManager.GPS_PROVIDER, 1000, 100, this)
    

    do not forget to check if gps is enabled or not before requesting location update by gps.

    Thanks for contributing an answer to Stack Overflow!

    • Please be sure to answer the question. Provide details and share your research!

    But avoid

    • Asking for help, clarification, or responding to other answers.
    • Making statements based on opinion; back them up with references or personal experience.

    To learn more, see our tips on writing great answers.