2010-03-23 5 views
19

У меня есть код Android, который должен получить лучшее доступное местоположение БЫСТРО, от GPS, сети или любого другого. Точность менее важна, чем скорость.Android: получите текущее местоположение от лучшего поставщика

Получение наилучшего доступного местоположения, безусловно, является действительно стандартной задачей. Тем не менее, я не могу найти код для его демонстрации. Код местоположения Android предполагает, что вы укажете критерии, зарегистрируйтесь для получения обновлений и подождите - это нормально, если у вас есть подробные критерии и вы не можете ждать.

Но мое приложение должно работать немного больше, как приложение Maps, когда оно сначала находит вас - работайте с любым доступным провайдером, и просто проверьте, что местоположение не дико устарело или null.

Я попытался свернуть свой собственный код, чтобы сделать это, но у меня проблемы. (Это внутри IntentService, где происходит загрузка, если это имеет значение. Я включил весь код для информации.) Что не так с этим кодом?

@Override 
protected void onHandleIntent(Intent arg0) { 
    testProviders(); 
    doUpload(); 
} 
private boolean doUpload() { 
     int j = 0; 
     // check if we have accurate location data yet - wait up to 30 seconds 
     while (j < 30) { 
      if ((latString == "") || (lonString == "")) { 
       Log.d(LOG_TAG, "latlng null"); 
       Thread.sleep(1000); 
       j++; 
     } else { 
       Log.d(LOG_TAG, "found lat " + latString + " and lon " + lonString); 
      break; 
     } 
     //do the upload here anyway, with or without location data 
     //[code removed for brevity] 
} 
public boolean testProviders() { 
    Log.e(LOG_TAG, "testProviders"); 
    String location_context = Context.LOCATION_SERVICE; 
    locationmanager = (LocationManager) getSystemService(location_context); 
    List<String> providers = locationmanager.getProviders(true); 
    for (String provider : providers) { 
     Log.e(LOG_TAG, "registering provider " + provider); 
     listener = new LocationListener() { 
      public void onLocationChanged(Location location) { 
       // keep checking the location - until we have 
       // what we need 
       //if (!checkLoc(location)) { 
       Log.e(LOG_TAG, "onLocationChanged"); 
       locationDetermined = checkLoc(location); 
       //} 
      } 
      public void onProviderDisabled(String provider) { 
      } 
      public void onProviderEnabled(String provider) { 
      } 
      public void onStatusChanged(String provider, int status, 
        Bundle extras) { 
      } 
     }; 
     locationmanager.requestLocationUpdates(provider, 0, 
       0, listener); 
    } 
    Log.e(LOG_TAG, "getting updates"); 
    return true; 
} 
private boolean checkLoc(Location location) { 
    float tempAccuracy = location.getAccuracy(); 
    int locAccuracy = (int) tempAccuracy; 
    Log.d(LOG_TAG, "locAccuracy = " + locAccuracy); 
    if ((locAccuracy != 0) && (locAccuracy < LOCATION_ACCURACY)) { 
     latitude = location.getLatitude(); 
     longitude = location.getLongitude(); 
     latString = latitude.toString(); 
     lonString = longitude.toString(); 
     return true; 
    } 
    return false; 
} 
public void removeListeners() { 
    // Log.e(LOG_TAG, "removeListeners"); 
    if ((locationmanager != null) && (listener != null)) { 
     locationmanager.removeUpdates(listener); 
    } 
    locationmanager = null; 
    // Log.d(LOG_TAG, "Removed " + listener.toString()); 
} 
@Override 
public void onDestroy() { 
    super.onDestroy(); 
    removeListeners(); 
} 

К сожалению, это находит сети провайдера, но только когда-либо выводит latlng null 30 раз - он никогда не кажется, чтобы получить место на всех. Я даже не получаю регистрационную запись locationChanged.

Это забавно, потому что с DDMS я вижу выход, как:

NetworkLocationProvider: onCellLocationChanged [305,8580] 
NetworkLocationProvider: getNetworkLocation(): returning cache location with accuracy 75.0 

кажущегося предположить, что провайдер сети имеет некоторую информацию о местоположении в конце концов, я просто не получить на него.

Может ли кто-нибудь помочь? Я думаю, что рабочий пример кода будет полезным ресурсом для сообщества Android/StackOverflow.

+0

Может быть, мой пример кода может помочь http://stackoverflow.com/ вопросы/3145089/what-is-the-simple-and-most-robust-way-to-get-the-users-current-location-in-an/3145655 # 3145655 – Fedor

ответ

5

Thread.sleep() в производственном коде является серьезным запахом кода ИМХО. Если вы обнаружите, что вам нужно это сделать, вы, вероятно, делаете то, что не должно работать так. В этом случае я думаю, что это источник вашей проблемы - вы не позволяете Android вернуться к обработке очереди сообщений этого потока, чтобы отправлять любые найденные им обновления местоположения. Я подозреваю, что IntentService просто не будет работать для вашего сценария.

+0

Спасибо. Думаю, я сделаю это в обычной деятельности и просто передам lat/lon в IntentService. Мне все еще действительно нравится пример того, как проверить все LocationProviders и выбрать лучшее место, хотя - если у кого-нибудь есть какой-либо пример кода, пожалуйста, опубликуйте его ... если нет, я попытаюсь что-то взломать и разместить здесь. – AP257

+0

@CommonsWare - как вы предлагаете мне реализовать следующее без использования Thread.sleep()? «Продолжайте проверять наличие обновлений местоположения в течение 30 секунд, если к тому времени не найдено ни одного обновленного местоположения, отказаться и использовать фиктивные значения». – AP257

+0

Существует миллион и одна причина, по которой Thread.sleep может использоваться в производственном коде (хотя я не говорю здесь обязательно). – monkjack

6

Вы определенно пытаетесь сделать это с трудом. Вот некоторые фрагменты нового приложения, над которым я работаю. Он использует Criteria, чтобы получить всех поставщиков, способных возвращать точный уровень точности без затрат.

Если ни один поставщик услуг не включен, отображается диалоговое окно с запросом на включение настроек местоположения. Если пользователь нажимает ok, на самом деле умышленно запущен Intent, который отправляет их в настройки на своем телефоне. Если есть поставщики, приложение принимает последние last known location от любого из разрешенных поставщиков. Для моего приложения мне просто нужно знать, в какой общей области находится пользователь, и вполне вероятно, что последнее известное местоположение находится из их родной области.

Если провайдеры включены, цикл также запрашивает обновления местоположения как можно быстрее. Это идеально подходит для моего приложения, но вы можете изменить это, чтобы сохранить батарею, меняя аргументы на requestLocationUpdates method.

Оптимизация, что этот код показывает, что примеры в приложении для Android действительно не показывают, что все включенные поставщики запущены одновременно. Все поставщики возвратят отдельные обновления на onLocationChanged method. В моем приложении я удаляю приемник местоположения после того, как один из провайдеров возвращает местоположение с достаточно хорошей точностью.

Старт Место Обновление:

void getCurrentLocation() { 
    List<String> providers = locationManager.getProviders(criteria, true); 
    if (providers != null) { 
     Location newestLocation = null; 
     for (String provider : providers) { 
      Location location = locationManager.getLastKnownLocation(provider); 
      if (location != null) { 
       if (newestLocation == null) { 
        newestLocation = location; 
       } else { 
        if (location.getTime() > newestLocation.getTime()) { 
         newestLocation = location; 
        } 
       } 
       locationManager.requestLocationUpdates(provider, 0, 0, this); 
      } 
     } 
    } else { 
     LocationDialogFragment dialog = new LocationDialogFragment(); 
     dialog.show(getSupportFragmentManager(), 
      LocationDialogFragment.class.getName()); 
    } 
} 

Получите Location Update:

@Override 
public void onLocationChanged(Location location) { 
    float bestAccuracy = -1f; 
    if (location.getAccuracy() != 0.0f 
     && (location.getAccuracy() < bestAccuracy) || bestAccuracy == -1f) { 
     if (location.getAccuracy() < Const.MIN_ACCURACY) { 
      locationManager.removeUpdates(this); 
     } 
    } 
    bestAccuracy = location.getAccuracy(); 
} 

Расположение Настройки Диалог:

public class LocationDialogFragment extends DialogFragment { 

    @Override 
    public Dialog onCreateDialog(Bundle savedInstanceState) { 
     AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); 
     builder.setMessage(R.string.location_dialog_message) 
       .setPositiveButton(R.string.location_dialog_positive_button, 
        new OnClickListener() { 

         @Override 
         public void onClick(DialogInterface dialog, int which) { 
          Intent settingsIntent = new Intent(
            Settings.ACTION_LOCATION_SOURCE_SETTINGS); 
          startActivity(settingsIntent); 
         } 
        }) 
       .setNegativeButton(R.string.location_dialog_negative_button, 
        new OnClickListener() { 

         @Override 
         public void onClick(DialogInterface dialog, int which) { 
          Toast.makeText(getActivity(), 
           R.string.no_location_message, Toast.LENGTH_LONG) 
            .show(); 
         } 
        }); 
     return builder.create(); 
    } 
} 
+0

Отличное решение! Только одна вещь, чтобы указать. Это может быть связано с изменением API, но условие '(providers! = Null)' должно быть '(privders.size()> 0)', потому что метод getProviders (Criteria, boolean) 'никогда не возвращается 'null', вместо этого он может возвращать список с размером 0. – luixal

+1

Я думаю, что я помню, что не был точен, когда я тестировал это, но я думаю, нам нужно пройти документацию. В любом случае, каждый должен знать, что FusedLocationProvider в библиотеке Google Play Services намного превосходит старые классы местоположения. Однако реализация сильно отличается. Этот метод немного устарел. – jophde

+0

Можете ли вы показать нам, как вы построили объект «Критерии» ... Мне также нужно приблизительное местоположение (точность города) – feresr

Смежные вопросы