2015-04-15 4 views
28

У меня есть приложение для Android, которому требуется текущее местоположение устройства (широта и долгота). Я пробовал некоторые учебные пособия в сети и особенно некоторые решения из переполнения стека, но они не работают хорошо для меня. Мое требование настолько простое: сначала мне нужно, чтобы оно было быстрым, и нужно одно место, когда я начну с фрагмента. Во-вторых, мне нужно, чтобы он был как можно более точным, я имею в виду, что он должен сначала использовать GPS, если GPS недоступен, а затем использовать Network provider.получить текущее местоположение быстро и один раз в android

Например, я пробовал this solution, но он возвращает null через 30 секунд, но я знаю, что есть все, что хорошо, потому что карта google и другое приложение хорошо работают !!!

Что-то, что почти все ответы указывают на использование getLastKnownLocation(), но я полагаю, что это не текущее, и я не хочу его, если это так.

Может ли кто-нибудь предложить мне какой-то простой и быстрый способ получить место только один раз?!

Заранее спасибо

ответ

46

Здесь вы можете использовать это ...

Пример использования:

public void foo(Context context) { 
    // when you need location 
    // if inside activity context = this; 

    SingleShotLocationProvider.requestSingleUpdate(context, 
    new SingleShotLocationProvider.LocationCallback() { 
    @Override public void onNewLocationAvailable(GPSCoordinates location) { 
     Log.d("Location", "my location is " + location.toString()); 
    } 
    }); 
} 

Вы можете проверить широту/долготу фактические значения, а не 0 или что-то. Если я правильно помню, это не должно бросать NPE, но вы можете проверить это.

public class SingleShotLocationProvider { 

    public static interface LocationCallback { 
     public void onNewLocationAvailable(GPSCoordinates location); 
    } 

    // calls back to calling thread, note this is for low grain: if you want higher precision, swap the 
    // contents of the else and if. Also be sure to check gps permission/settings are allowed. 
    // call usually takes <10ms 
    public static void requestSingleUpdate(final Context context, final LocationCallback callback) { 
     final LocationManager locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE); 
     boolean isNetworkEnabled = locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER); 
     if (isNetworkEnabled) { 
      Criteria criteria = new Criteria(); 
      criteria.setAccuracy(Criteria.ACCURACY_COARSE); 
      locationManager.requestSingleUpdate(criteria, new LocationListener() { 
       @Override 
       public void onLocationChanged(Location location) { 
        callback.onNewLocationAvailable(new GPSCoordinates(location.getLatitude(), location.getLongitude())); 
       } 

       @Override public void onStatusChanged(String provider, int status, Bundle extras) { } 
       @Override public void onProviderEnabled(String provider) { } 
       @Override public void onProviderDisabled(String provider) { } 
      }, null); 
     } else { 
      boolean isGPSEnabled = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER); 
      if (isGPSEnabled) { 
       Criteria criteria = new Criteria(); 
       criteria.setAccuracy(Criteria.ACCURACY_FINE); 
       locationManager.requestSingleUpdate(criteria, new LocationListener() { 
        @Override 
        public void onLocationChanged(Location location) { 
         callback.onNewLocationAvailable(new GPSCoordinates(location.getLatitude(), location.getLongitude())); 
        } 

        @Override public void onStatusChanged(String provider, int status, Bundle extras) { } 
        @Override public void onProviderEnabled(String provider) { } 
        @Override public void onProviderDisabled(String provider) { } 
       }, null); 
      } 
     } 
    } 


    // consider returning Location instead of this dummy wrapper class 
    public static class GPSCoordinates { 
     public float longitude = -1; 
     public float latitude = -1; 

     public GPSCoordinates(float theLatitude, float theLongitude) { 
      longitude = theLongitude; 
      latitude = theLatitude; 
     } 

     public GPSCoordinates(double theLatitude, double theLongitude) { 
      longitude = (float) theLongitude; 
      latitude = (float) theLatitude; 
     } 
    } 
} 
+3

Он работает как шарм, это достаточно быстро для меня, спасибо много. – Evil

+0

не работает, мне нужно добавить в манифест? – delive

+1

Очень полезно. Спасибо. –

1

То, что вы хотите сделать, это достигается с помощью LocationManager#requestSingleUpdate. Этот метод присоединяет слушателя в заданном петлителе (если вы хотите его или нет) и уведомляет местоположение ASAP, которое оно получено, только один раз. Метод, который вы предлагаете, используется только как неточное положение до того, как вам будет дан реальный.

В любом случае это будет быстро, чем миллисекунды (если вам не посчастливилось начать прослушивание, когда на устройство поступило местоположение). Подумайте о GPS как о элементе, который вы активируете при ожидании местоположений и отключите, когда вы удалите это прослушивание. Это делается для того, чтобы не разряжать аккумулятор пользователя.

Итак, подведем итог:

  • время между вами начать слушать, и вы получите положение зависит от устройства GPS (производство, местоположение пользователя, покрытия спутника ...)
  • Там это метод в Android SDK для прослушивания одного обновления.
  • Предоставляя объект критериев, вы можете управлять тем, какие критерии приемлемы для вас, чтобы получить местоположение. Более сильные критерии означают больше времени для получения точного ответа.
0
// Get LocationManager object 
    LocationManager locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE); 

    // Create a criteria object to retrieve provider 
    Criteria criteria = new Criteria(); 

    // Get the name of the best provider 
    String provider = locationManager.getBestProvider(criteria, true); 

    // Get Current Location 
    Location myLocation = locationManager.getLastKnownLocation(provider); 

    //latitude of location 
    double myLatitude = myLocation.getLatitude(); 

    //longitude og location 
    double myLongitude = myLocation.getLongitude(); 

    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 
     // ActivityCompat#requestPermissions 
     // here to request the missing permissions, and then overriding 
     // public void onRequestPermissionsResult(int requestCode, String[] permissions, 
     //           int[] grantResults) 
     // to handle the case where the user grants the permission. See the documentation 
     // for ActivityCompat#requestPermissions for more details. 
     return; 
    } 
+0

Почему оператор if использует '&&', а не '||' ? вам нужно только одно из разрешений для доступа к местоположению? – DAVIDBALAS1

1

AndroidManifest.xml:

<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> 
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> 
<uses-feature android:name="android.hardware.location.gps" /> 

MainActivity.java:

public class MainActivity extends AppCompatActivity implements LocationListener { 

    private LocationManager locationManager; 
    private Location onlyOneLocation; 
    private final int REQUEST_FINE_LOCATION = 1234; 

    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.activity_main); 
     if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) 
      ActivityCompat.requestPermissions(this, new String[] {Manifest.permission.ACCESS_FINE_LOCATION}, REQUEST_FINE_LOCATION); 
    } 

    @Override public void onLocationChanged(Location location) { 
     onlyOneLocation = location; 
     locationManager.removeUpdates(this); 
    } 
    @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 onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) { 
     switch (requestCode) { 
     case REQUEST_FINE_LOCATION: 
      if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { 
       Log.d("gps", "Location permission granted"); 
       try { 
        locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE); 
        locationManager.requestLocationUpdates("gps", 0, 0, this); 
       } 
       catch (SecurityException ex) { 
        Log.d("gps", "Location permission did not work!"); 
       } 
      } 
      break; 
    } 
} 
1

AndroidManifest.XML

<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> 
<uses-feature android:name="android.hardware.location.gps" /> 

Requesting User Permissions


build.gradle (Module: приложение)

dependencies { 
    ... 
    implementation 'com.google.android.gms:play-services-location:11.8.0' 
    ... 
} 

Если вы получите сообщение об ошибке, проверьте ТНА т верхнего уровня, build.gradle содержит ссылку на Google() репо или Maven {URL "https://maven.google.com"}

Set Up Google Play Services


LocationService.kt

import android.Manifest 
import android.annotation.SuppressLint 
import android.app.Activity 
import android.content.Intent 
import android.content.pm.PackageManager 
import android.location.Location 
import android.net.Uri 
import android.os.Looper 
import android.provider.Settings 
import android.support.v4.app.ActivityCompat 
import android.support.v4.content.ContextCompat 
import com.google.android.gms.common.api.ApiException 
import com.google.android.gms.common.api.ResolvableApiException 
import com.google.android.gms.location.* 
import org.jetbrains.anko.alert 
import org.jetbrains.anko.doAsync 
import org.jetbrains.anko.okButton 

object LocationService { 

    @SuppressLint("StaticFieldLeak") 
    private lateinit var fusedLocationProviderClient: FusedLocationProviderClient 
    private lateinit var locationRequest: LocationRequest 
    private val locationCallback = object : LocationCallback() { 
     override fun onLocationResult(locationResult: LocationResult) { 
      doAsync { 
       location = locationResult.lastLocation 
       onSuccess(location) 
      } 
     } 
    } 
    private lateinit var onSuccess: (location : Location) -> Unit 
    private lateinit var onError:() -> Unit 
    lateinit var location: Location 

    fun init(activity: Activity) { 
     fusedLocationProviderClient = FusedLocationProviderClient(activity) 
     locationRequest = LocationRequest().setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY).setInterval(1000).setFastestInterval(1000).setNumUpdates(1) 
    } 

    private fun checkLocationStatusAndGetLocation(activity: Activity) { 
     doAsync { 
      when { 
       ContextCompat.checkSelfPermission(activity, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED -> LocationServices.getSettingsClient(activity).checkLocationSettings(LocationSettingsRequest.Builder().addLocationRequest(locationRequest).setAlwaysShow(true).build()).addOnCompleteListener { task -> 
        doAsync { 
         try { 
          task.getResult(ApiException::class.java) 
          fusedLocationProviderClient.requestLocationUpdates(locationRequest, locationCallback, Looper.getMainLooper()) 
         } catch (exception: ApiException) { 
          when (exception.statusCode) { 
           LocationSettingsStatusCodes.RESOLUTION_REQUIRED -> { 
            try { 
             (exception as ResolvableApiException).startResolutionForResult(activity, 7025) 
            } catch (ex: Exception) { 
             promptShowLocation(activity) 
            } 
           } 
           LocationSettingsStatusCodes.SETTINGS_CHANGE_UNAVAILABLE -> { 
            promptShowLocation(activity) 
           } 
          } 
         } 
        } 
       } 
       ActivityCompat.shouldShowRequestPermissionRationale(activity, Manifest.permission.ACCESS_FINE_LOCATION) -> activity.runOnUiThread { 
        activity.alert("To continue, allow the device to use location, witch uses Google's Location Service") { 
         okButton { 
          val ite = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS, Uri.fromParts("package", activity.packageName, null)) 
          ite.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) 
          activity.startActivity(ite) 
          onError() 
         } 
         negativeButton("Cancelar", { onError() }) 
         onCancelled { onError() } 
        }.show() 
       } 
       else -> ActivityCompat.requestPermissions(activity, arrayOf(Manifest.permission.ACCESS_FINE_LOCATION), 7024) 
      } 
     } 
    } 

    private fun promptShowLocation(activity: Activity) { 
     activity.runOnUiThread { 
      activity.alert("To continue, allow the device to use location, witch uses Google's Location Service") { 
       okButton { 
        activity.startActivity(Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS)) 
        onError() 
       } 
       negativeButton("Cancelar", { onError() }) 
       onCancelled { onError() } 
      }.show() 
     } 
    } 

    fun onRequestPermissionsResult(activity: Activity, requestCode: Int, grantResults: IntArray) { 
     if (requestCode == 7024) { 
      if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) { 
       checkLocationStatusAndGetLocation(activity) 
      } else { 
       onError() 
      } 
     } 
    } 

    fun onActivityResult(activity: Activity, requestCode: Int, resultCode: Int) { 
     if (requestCode == 7025) { 
      if (resultCode == Activity.RESULT_OK) { 
       checkLocationStatusAndGetLocation(activity) 
      } else { 
       onError() 
      } 
     } 
    } 

    fun getLocation(activity: Activity, onSuccess:() -> Unit, onError:() -> Unit) { 
     this.onSuccess = onSuccess 
     this.onError = onError 
     checkLocationStatusAndGetLocation(activity) 
    } 

} 

Ваша деятельность

override fun onCreate(savedInstanceState: Bundle?) { 
    ... 
    LocationService.init(this) 
} 

override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>, grantResults: IntArray) { 
    super.onRequestPermissionsResult(requestCode, permissions, grantResults) 
    LocationService.onRequestPermissionsResult(this, requestCode, grantResults) 
} 

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { 
    super.onActivityResult(requestCode, resultCode, data) 
    LocationService.onActivityResult(this, requestCode, resultCode) 
} 

private fun yourFunction() { 
    LocationService.getLocation(this, { location -> 
     //TODO: use the location 
    }, { 
     //TODO: display error message 
    }) 
} 
Смежные вопросы