在 Android 上获取用户当前位置的最简单、最可靠的方法是啥?
Posted
技术标签:
【中文标题】在 Android 上获取用户当前位置的最简单、最可靠的方法是啥?【英文标题】:What is the simplest and most robust way to get the user's current location on Android?在 Android 上获取用户当前位置的最简单、最可靠的方法是什么? 【发布时间】:2011-03-09 20:59:22 【问题描述】:android 上的 LocationManager
API 对于只需要偶尔粗略估计用户位置的应用程序似乎有点痛苦。
我正在开发的应用本身并不是真正的定位应用,但它确实需要获取用户的位置才能显示附近商家的列表。它不需要担心用户是否在四处走动或类似的事情。
这是我想做的:
-
向用户显示附近位置的列表。
预加载用户的位置,这样当我在
Activity
X 中需要它时,它就可用了。
我并不特别关心更新的准确性或频率。只要不远,只需抓住一个位置就足够了。也许如果我想变得漂亮,我会每隔几分钟左右更新一次位置,但这不是一个重要的优先事项。
适用于任何具有 GPS 或网络位置提供程序的设备。
看起来应该没那么难,但在我看来,我必须启动两个不同的位置提供程序(GPS 和 NETWORK)并管理每个位置的生命周期。不仅如此,我还必须在多个活动中复制相同的代码以满足#2。我过去曾尝试使用getBestProvider()
将解决方案缩减为仅使用一个位置提供程序,但这似乎只会为您提供最佳的“理论”提供程序,而不是实际上会为您提供最佳结果的提供程序。
有没有更简单的方法来做到这一点?
【问题讨论】:
您可以使用一个简单的库来抽象出所有必须在“幕后”发生的事情:github.com/delight-im/Android-SimpleLocation 在这里获得 Kotlin 的答案:***.com/a/53800632/2201814 你可以在android中使用融合位置捕获技术。 FusedLocation 工作正常(我仍然不知道为什么必须弃用 getCurrentLocation())。 【参考方案1】:在搜索了如何获得最佳精确用户位置的最佳实现之后,我设法结合了所有最好的方法并提出了以下类:
/**
* Retrieve accurate location from GPS or network services.
*
*
* Class usage example:
*
* public void onCreate(Bundle savedInstanceState)
* ...
* my_location = new MyLocation();
* my_location.init(main.this, locationResult);
*
*
*
* public LocationResult locationResult = new LocationResult()
* @Override
* public void gotLocation(final Location location)
* // do something
* location.getLongitude();
* location.getLatitude();
*
* ;
*/
class MyLocation
/**
* If GPS is enabled.
* Use minimal connected satellites count.
*/
private static final int min_gps_sat_count = 5;
/**
* Iteration step time.
*/
private static final int iteration_timeout_step = 500;
LocationResult locationResult;
private Location bestLocation = null;
private Handler handler = new Handler();
private LocationManager myLocationManager;
public Context context;
private boolean gps_enabled = false;
private int counts = 0;
private int sat_count = 0;
private Runnable showTime = new Runnable()
public void run()
boolean stop = false;
counts++;
System.println("counts=" + counts);
//if timeout (1 min) exceeded, stop tying
if(counts > 120)
stop = true;
//update last best location
bestLocation = getLocation(context);
//if location is not ready or don`t exists, try again
if(bestLocation == null && gps_enabled)
System.println("BestLocation not ready, continue to wait");
handler.postDelayed(this, iteration_timeout_step);
else
//if best location is known, calculate if we need to continue to look for better location
//if gps is enabled and min satellites count has not been connected or min check count is smaller then 4 (2 sec)
if(stop == false && !needToStop())
System.println("Connected " + sat_count + " sattelites. continue waiting..");
handler.postDelayed(this, iteration_timeout_step);
else
System.println("#########################################");
System.println("BestLocation found return result to main. sat_count=" + sat_count);
System.println("#########################################");
// removing all updates and listeners
myLocationManager.removeUpdates(gpsLocationListener);
myLocationManager.removeUpdates(networkLocationListener);
myLocationManager.removeGpsStatusListener(gpsStatusListener);
sat_count = 0;
// send best location to locationResult
locationResult.gotLocation(bestLocation);
;
/**
* Determine if continue to try to find best location
*/
private Boolean needToStop()
if(!gps_enabled)
return true;
else if(counts <= 4)
return false;
if(sat_count < min_gps_sat_count)
//if 20-25 sec and 3 satellites found then stop
if(counts >= 40 && sat_count >= 3)
return true;
return false;
return true;
/**
* Best location abstract result class
*/
public static abstract class LocationResult
public abstract void gotLocation(Location location);
/**
* Initialize starting values and starting best location listeners
*
* @param Context ctx
* @param LocationResult result
*/
public void init(Context ctx, LocationResult result)
context = ctx;
locationResult = result;
myLocationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
gps_enabled = (Boolean) myLocationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
bestLocation = null;
counts = 0;
// turning on location updates
myLocationManager.requestLocationUpdates("network", 0, 0, networkLocationListener);
myLocationManager.requestLocationUpdates("gps", 0, 0, gpsLocationListener);
myLocationManager.addGpsStatusListener(gpsStatusListener);
// starting best location finder loop
handler.postDelayed(showTime, iteration_timeout_step);
/**
* GpsStatus listener. OnChainged counts connected satellites count.
*/
public final GpsStatus.Listener gpsStatusListener = new GpsStatus.Listener()
public void onGpsStatusChanged(int event)
if(event == GpsStatus.GPS_EVENT_SATELLITE_STATUS)
try
// Check number of satellites in list to determine fix state
GpsStatus status = myLocationManager.getGpsStatus(null);
Iterable<GpsSatellite>satellites = status.getSatellites();
sat_count = 0;
Iterator<GpsSatellite>satI = satellites.iterator();
while(satI.hasNext())
GpsSatellite satellite = satI.next();
System.println("Satellite: snr=" + satellite.getSnr() + ", elevation=" + satellite.getElevation());
sat_count++;
catch (Exception e)
e.printStackTrace();
sat_count = min_gps_sat_count + 1;
System.println("#### sat_count = " + sat_count);
;
/**
* Gps location listener.
*/
public final LocationListener gpsLocationListener = new LocationListener()
@Override
public void onLocationChanged(Location location)
public void onProviderDisabled(String provider)
public void onProviderEnabled(String provider)
public void onStatusChanged(String provider, int status, Bundle extras)
;
/**
* Network location listener.
*/
public final LocationListener networkLocationListener = new LocationListener()
@Override
public void onLocationChanged(Location location)
public void onProviderDisabled(String provider)
public void onProviderEnabled(String provider)
public void onStatusChanged(String provider, int status, Bundle extras)
;
/**
* Returns best location using LocationManager.getBestProvider()
*
* @param context
* @return Location|null
*/
public static Location getLocation(Context context)
System.println("getLocation()");
// fetch last known location and update it
try
LocationManager lm = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
Criteria criteria = new Criteria();
criteria.setAccuracy(Criteria.ACCURACY_FINE);
criteria.setAltitudeRequired(false);
criteria.setBearingRequired(false);
criteria.setCostAllowed(true);
String strLocationProvider = lm.getBestProvider(criteria, true);
System.println("strLocationProvider=" + strLocationProvider);
Location location = lm.getLastKnownLocation(strLocationProvider);
if(location != null)
return location;
return null;
catch (Exception e)
e.printStackTrace();
return null;
如果启用了 GPS,则此类尝试连接到 min_gps_sat_count
卫星。否则返回LocationManager.getBestProvider()
位置。检查代码!
【讨论】:
它将在 1 分钟后或找到位置后停止。 @wormhit 在我的情况下,它不会在 120 计数后停止。我已经启用了 GPS,网络提供商也可用,我也在 Menifest 文件中添加了适当的权限。 只需将这些作为导入:import java.util.Iterator; import android.content.Context; import android.location.Criteria; import android.location.GpsSatellite; import android.location.GpsStatus; import android.location.Location; import android.location.LocationListener; import android.location.LocationManager; import android.os.Bundle; import android.os.Handler;
【参考方案2】:
我使用了这个 GPS 追踪器,它从 Android API 21 到 30 运行良好:
即使网络被禁用并启用 GPS 也能正常工作 如果两者都启用也可以使用:) 如果未启用 GPS,则会提示启用 GPS,并将用户带到 GPS 设置 获取位置更改后的位置更新 可以通过经纬度获取地址 优先考虑网络提供商并减少电池消耗 您可以随时停止位置更新。进口:
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Service;
import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
import android.content.Intent;
import android.location.Geocoder;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.os.IBinder;
import android.provider.Settings;
import android.util.Log;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GoogleApiAvailability;
import java.util.List;
import java.util.Objects;
这是 GPSTracker 类:
public class GPSTracker extends Service implements LocationListener,
OnClickListener
private final Context mContext;
private Location location = null;
protected LocationManager locationManager;
private double latitude;
private double longitude;
private boolean isGPSEnabled = false;
private boolean canGetLocation = false;
private static final long MIN_DISTANCE_CHANGE_FOR_UPDATES = 10; // 10 meters
private static final long MIN_TIME_BW_UPDATES = 1000 * 60; // 1 minute
private final String TAG = "GPSTracker";
public GPSTracker(Context context)
mContext = context;
getLocation();
public Location getLocation()
try
locationManager = (LocationManager) mContext.getSystemService(LOCATION_SERVICE);
// getting GPS status
isGPSEnabled = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
// getting network status
boolean isNetworkEnabled = locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
if (isGPSEnabled || isNetworkEnabled)
this.canGetLocation = true;
// if Network enabled lat/long using Network Provider
if (isNetworkEnabled)
Log.d(TAG, "Network Provider");
if (locationManager != null)
locationManager.requestLocationUpdates(
LocationManager.NETWORK_PROVIDER,
MIN_TIME_BW_UPDATES,
MIN_DISTANCE_CHANGE_FOR_UPDATES, this);
location = locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
if (location != null)
latitude = location.getLatitude();
longitude = location.getLongitude();
else // if GPS Enabled get lat/long using GPS Services
Log.d(TAG, "GPS Provider");
locationManager.requestLocationUpdates(
LocationManager.GPS_PROVIDER,
MIN_TIME_BW_UPDATES,
MIN_DISTANCE_CHANGE_FOR_UPDATES, this);
if (locationManager != null)
location = locationManager
.getLastKnownLocation(LocationManager.GPS_PROVIDER);
if (location != null)
latitude = location.getLatitude();
longitude = location.getLongitude();
else
showSettingsAlert(this, this);
catch (SecurityException e)
e.printStackTrace();
return location;
@Override
public void onLocationChanged(Location location)
latitude = location.getLatitude();
longitude = location.getLongitude();
Log.d(TAG, "Location changed: latitude: " + latitude + " , longitude: " + longitude);
@Override
public void onProviderDisabled(String provider)
Log.d(TAG, "onProviderDisabled called");
@Override
public void onProviderEnabled(String provider)
Log.d(TAG, "onProviderEnabled called");
@Override
public void onStatusChanged(String provider, int status, Bundle extras)
@Override
public IBinder onBind(Intent arg0)
return null;
/**
* Function to get latitude
*/
public double getLatitude()
if (location != null)
latitude = location.getLatitude();
return latitude;
/**
* Function to get longitude
*/
public double getLongitude()
if (location != null)
longitude = location.getLongitude();
return longitude;
/**
* Function to check if best network provider
*
* @return boolean
*/
public boolean canGetLocation()
return this.canGetLocation;
/**
* Function to show settings alert dialog
*/
public AlertDialog showSettingsAlert(
OnClickListener _positiveButtonClickListener,
OnClickListener _negativeButtonClickListener)
AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(mContext);
// Setting Dialog Title
alertDialogBuilder.setTitle("GPS settings");
// Setting Dialog Message
alertDialogBuilder.setMessage("Please enable GPS to proceed.");
// On pressing Settings button
alertDialogBuilder.setPositiveButton("Settings",
_positiveButtonClickListener);
// on pressing cancel button
alertDialogBuilder.setNegativeButton("Cancel", _negativeButtonClickListener);
alertDialogBuilder.setCancelable(false);
AlertDialog alertDialog = alertDialogBuilder.create();
// Showing Alert Message
alertDialogBuilder.show();
return alertDialog;
/**
* Function to show settings alert dialog
*/
public AlertDialog showGPSOffSettingsAlert(
OnClickListener _positiveButtonClickListener,
OnClickListener _negativeButtonClickListener)
AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(mContext);
// Setting Dialog Title
alertDialogBuilder.setTitle("GPS settings");
// Setting Dialog Message
alertDialogBuilder.setMessage("Do you want to turn off GPS?");
// On pressing Settings button
alertDialogBuilder.setPositiveButton("Settings", _positiveButtonClickListener);
// on pressing cancel button
alertDialogBuilder.setNegativeButton("Cancel", _negativeButtonClickListener);
alertDialogBuilder.setCancelable(false);
AlertDialog alertDialog = alertDialogBuilder.create();
// Showing Alert Message
alertDialogBuilder.show();
return alertDialog;
/**
* Stop using GPS listener Calling this function will stop using GPS in your
* app
*/
public void stopUsingGPS()
if (locationManager != null)
locationManager.removeUpdates(GPSTracker.this);
public boolean isGPSEnabled()
return isGPSEnabled;
public boolean isGooglePlayServicesAvailable()
GoogleApiAvailability googleApiAvailability = GoogleApiAvailability.getInstance();
int status = googleApiAvailability.isGooglePlayServicesAvailable(mContext);
if (status != ConnectionResult.SUCCESS)
if (googleApiAvailability.isUserResolvableError(status))
Objects.requireNonNull(googleApiAvailability.getErrorDialog((Activity) mContext, status, 2404)).show();
return false;
return true;
public Address getAddress(double latitude, double longitude)
boolean networkAvailable = AppUtils.INSTANCE.isNetworkAvailable(mContext);
Address address = new Address();
if (!networkAvailable)
return address;
Geocoder geocoder = new Geocoder(mContext);
try
List<android.location.Address> fromLocation = geocoder.getFromLocation(latitude, longitude, 1);
if (fromLocation != null && !fromLocation.isEmpty())
android.location.Address geoAddress = fromLocation.get(0);
address.setAddress(geoAddress.getAddressLine(0));
address.setCity(geoAddress.getLocality());
address.setCountry(geoAddress.getCountryName());
address.setPostalCode(geoAddress.getPostalCode());
address.setKnownName(geoAddress.getFeatureName());
address.setState(geoAddress.getAdminArea());
address.setCountryCode(geoAddress.getCountryCode());
address.setArea(geoAddress.getSubLocality());
catch (Exception e)
e.printStackTrace();
return address;
@Override
public void onClick(DialogInterface dialog, int which)
if (which == dialog.BUTTON_POSITIVE)
mContext.startActivity(new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS));
dialog.dismiss();
从您的活动中获取位置,例如:
private fun getLocationInfo()
val gpsTracker = GPSTracker(this)
if (gpsTracker.canGetLocation() && gpsTracker.isGooglePlayServicesAvailable)
val latitude = gpsTracker.latitude
val longitude = gpsTracker.longitude
val address = gpsTracker.getAddress(latitude, longitude)
FileLogUtil(this).logInfo(
"GPSTracker",
"Latitude: $latitude , Longitude: $longitude , Address: $address.address"
)
地址类:
public class Address
private String address;
private String city;
private String state;
private String country;
private String postalCode;
private String knownName;
private String countryCode;
private String area;
public String getAddress()
return address;
public void setAddress(String address)
this.address = address;
public String getCity()
return city;
public void setCity(String city)
this.city = city;
public String getState()
return state;
public void setState(String state)
this.state = state;
public String getCountry()
return country;
public void setCountry(String country)
this.country = country;
public String getPostalCode()
return postalCode;
public void setPostalCode(String postalCode)
this.postalCode = postalCode;
public String getKnownName()
return knownName;
public void setKnownName(String knownName)
this.knownName = knownName;
public String getCountryCode()
return countryCode;
public void setCountryCode(String countryCode)
this.countryCode = countryCode;
public String getArea()
return area;
public void setArea(String area)
this.area = area;
像这样检查网络提供商:
fun isNetworkAvailable(context: Context): Boolean
val connectivityManager =
context.getSystemService(AppCompatActivity.CONNECTIVITY_SERVICE) as ConnectivityManager
val activeNetworkInfo = connectivityManager.activeNetworkInfo
return activeNetworkInfo != null && activeNetworkInfo.isConnected
不要忘记在 Manifest 中添加这些权限:
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="com.google.android.providers.gsf.permission.READ_GSERVICES" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
我们可以使用它来请求所需的权限:
import android.Manifest
import android.app.Activity
import android.content.Context
import android.content.pm.PackageManager
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import java.util.*
class PermissionUtils(var activity: Activity)
private var permissionsList = arrayListOf<String>()
companion object
const val REQUEST_CODE_ASK_MULTIPLE_PERMISSIONS = 124
const val REQUEST_CALL_PERMISSION = 4
fun isPermissionGranted(context: Context, permission: String): Boolean
val res = context.checkCallingOrSelfPermission(permission)
return res == PackageManager.PERMISSION_GRANTED
fun requestForAllMandatoryPermissions()
permissionsList = ArrayList<String>()
//addPermissionIfNotGranted(Manifest.permission.CAMERA)
//addPermissionIfNotGranted(Manifest.permission.CALL_PHONE)
addPermissionIfNotGranted(Manifest.permission.ACCESS_FINE_LOCATION)
addPermissionIfNotGranted(Manifest.permission.ACCESS_COARSE_LOCATION)
//addPermissionIfNotGranted(Manifest.permission.READ_PHONE_STATE)
//addPermissionIfNotGranted(Manifest.permission.READ_EXTERNAL_STORAGE)
//addPermissionIfNotGranted(Manifest.permission.WRITE_EXTERNAL_STORAGE)
if (permissionsList.isNotEmpty())
ActivityCompat.requestPermissions(
activity,
permissionsList.toTypedArray(),
REQUEST_CODE_ASK_MULTIPLE_PERMISSIONS
)
private fun addPermissionIfNotGranted(permission: String)
if (ContextCompat.checkSelfPermission(activity, permission) !=
PackageManager.PERMISSION_GRANTED
)
permissionsList.add(permission)
ActivityCompat.shouldShowRequestPermissionRationale(activity, permission)
从您的活动中调用权限:
if (Build.VERSION.SDK_INT >= 23)
try
val permissionUtils = PermissionUtils(this)
permissionUtils.requestForAllMandatoryPermissions()
catch (e: Exception)
e.printStackTrace()
【讨论】:
【参考方案3】:其中一些答案现在已经过时了,所以我在回答,
FusedLocationProviderClient fusedLocationProviderClient; //set global variable
Location currentLocation;//set global var
private boolean mLocationPermissionGranted; //set global var
fusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(getContext()); //write this oncreate
fetchLastLocation(); // call the funct for current location
//here is the function
private void fetchLastLocation()
if (ActivityCompat.checkSelfPermission(getContext(), Manifest.permission.ACCESS_FINE_LOCATION)
!= PackageManager.PERMISSION_GRANTED)
ActivityCompat.requestPermissions(getActivity(),new String[]
Manifest.permission.ACCESS_FINE_LOCATION,REQUEST_CODE);
return;
else
mLocationPermissionGranted=true;
Task<Location> task= fusedLocationProviderClient.getLastLocation();
task.addOnSuccessListener(new OnSuccessListener<Location>()
@Override
public void onSuccess(Location location)
if(location != null)
currentLocation =location;
Toast.makeText(getContext(), currentLocation.getLatitude()+"" +
" "+currentLocation.getLongitude(),
Toast.LENGTH_SHORT).show();
//if you want to show in google maps
SupportMapFragment supportMapFragment =(SupportMapFragment)
getChildFragmentManager().findFragmentById(R.id.map);
supportMapFragment.getMapAsync(MapsFragment.this);
);
【讨论】:
如果location == null
怎么办?
融合的位置提供者最好获取位置,您也可以使用地理位置,,由于不同的原因,位置可能为空,可能是您没有连接到网络,所以在这种情况下您需要照顾互联网连接,如果位置为空,您可以向用户传递有关原因的消息。或者您可以多次调用此函数,除非您的位置不为空。
谢谢!可能有很多情况。我在旧模拟器上遇到了这个问题(并没有解决它。即使LocationManager
也没有帮助)。另请参阅***.com/questions/52587361/…、***.com/questions/47521121/…。【参考方案4】:
@Fedor 解决方案的改进。 我们可以使用位置管理器的 requestSingleUpdate 方法,而不是使用“0”时间间隔和“0”距离请求位置。更新代码(kotlin 版本)
import android.annotation.SuppressLint
import android.content.Context
import android.location.Criteria
import android.location.Location
import android.location.LocationListener
import android.location.LocationManager
import android.os.Bundle
import java.util.*
@SuppressLint("MissingPermission")
class AppLocationProvider
private lateinit var timer: Timer
private var locationManager: LocationManager? = null
private lateinit var locationCallBack: LocationCallBack
private var gpsEnabled = false
private var networkEnabled = false
private var locationListener: LocationListener = object : LocationListener
override fun onLocationChanged(location: Location)
timer.cancel()
locationCallBack.locationResult(location)
override fun onProviderDisabled(provider: String)
override fun onProviderEnabled(provider: String)
override fun onStatusChanged(provider: String, status: Int, extras: Bundle)
fun getLocation(context : Context, callBack: LocationCallBack): Boolean
locationCallBack = callBack
if (locationManager == null)
locationManager = context.getSystemService(Context.LOCATION_SERVICE) as LocationManager?
//exceptions will be thrown if provider is not permitted.
try
gpsEnabled = locationManager!!.isProviderEnabled(LocationManager.GPS_PROVIDER)
catch (ex: Exception)
ex.printStackTrace()
try
networkEnabled = locationManager!!.isProviderEnabled(LocationManager.NETWORK_PROVIDER)
catch (ex: Exception)
ex.printStackTrace()
//don't start listeners if no provider is enabled
if (!gpsEnabled && !networkEnabled)
return false
val criteria = Criteria()
if (gpsEnabled)
criteria.accuracy = Criteria.ACCURACY_FINE
else
criteria.accuracy = Criteria.ACCURACY_COARSE
locationManager!!.requestSingleUpdate(criteria, locationListener, null)
timer = Timer()
timer.schedule(GetLastKnownLocation(), 5000)
return true
inner class GetLastKnownLocation : TimerTask()
override fun run()
locationManager!!.removeUpdates(locationListener)
var netLoc: Location? = null
var gpsLoc: Location? = null
if (gpsEnabled)
gpsLoc = locationManager!!.getLastKnownLocation(LocationManager.GPS_PROVIDER)
if (networkEnabled)
netLoc = locationManager!!.getLastKnownLocation(LocationManager.NETWORK_PROVIDER)
//check which value use the latest one
if (gpsLoc != null && netLoc != null)
if (gpsLoc.time > netLoc.time)
locationCallBack.locationResult(gpsLoc)
else
locationCallBack.locationResult(netLoc)
return
if (gpsLoc != null)
locationCallBack.locationResult(gpsLoc)
return
if (netLoc != null)
locationCallBack.locationResult(netLoc)
return
locationCallBack.locationResult(null)
interface LocationCallBack
fun locationResult(location: Location?)
要获取位置只需调用 getLocation 方法 -
AppLocationProvider().getLocation(context, object : AppLocationProvider.LocationCallBack
override fun locationResult(location: Location?)
// use location, this might get called in a different thread if a location is a last known location. In that case, you can post location on main thread
)
注意: 在调用 getLocation 方法之前,必须授予所需的位置权限。
【讨论】:
LocationManager.requestSingleUpdate
现已在 2021 年弃用。【参考方案5】:
在Activity Class中自定义方法:
private void getTheUserPermission()
ActivityCompat.requestPermissions(this, new String[]
Manifest.permission.ACCESS_FINE_LOCATION, REQUEST_LOCATION);
locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
LocationGetter locationGetter = new LocationGetter(FreshMenuSearchActivity.this, REQUEST_LOCATION, locationManager);
if (!locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER))
locationGetter.OnGPS();
else
locationGetter.getLocation();
创建一个 UserDefined 类名 LocationGetter:-
public class LocationGetter
private int REQUEST_LOCATION;
private FreshMenuSearchActivity mContext;
private LocationManager locationManager;
private Geocoder geocoder;
public LocationGetter(FreshMenuSearchActivity mContext, int requestLocation, LocationManager locationManager)
this.mContext = mContext;
this.locationManager = locationManager;
this.REQUEST_LOCATION = requestLocation;
public void getLocation()
if (ActivityCompat.checkSelfPermission(mContext, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(mContext,
Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED)
ActivityCompat.requestPermissions(mContext, new String[]
Manifest.permission.ACCESS_FINE_LOCATION, REQUEST_LOCATION);
else
Location LocationGps = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
Location LocationNetwork = locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
Location LocationPassive = locationManager.getLastKnownLocation(LocationManager.PASSIVE_PROVIDER);
if (LocationGps != null)
double lat = LocationGps.getLatitude();
double longi = LocationGps.getLongitude();
getTheAddress(lat, longi);
else if (LocationNetwork != null)
double lat = LocationNetwork.getLatitude();
double longi = LocationNetwork.getLongitude();
getTheAddress(lat, longi);
else if (LocationPassive != null)
double lat = LocationPassive.getLatitude();
double longi = LocationPassive.getLongitude();
getTheAddress(lat, longi);
else
Toast.makeText(mContext, "Can't Get Your Location", Toast.LENGTH_SHORT).show();
private void getTheAddress(double latitude, double longitude)
List<Address> addresses;
geocoder = new Geocoder(mContext, Locale.getDefault());
try
addresses = geocoder.getFromLocation(latitude, longitude, 1);
String address = addresses.get(0).getAddressLine(0);
String city = addresses.get(0).getLocality();
String state = addresses.get(0).getAdminArea();
String country = addresses.get(0).getCountryName();
String postalCode = addresses.get(0).getPostalCode();
String knownName = addresses.get(0).getFeatureName();
Log.d("neel", address);
catch (IOException e)
e.printStackTrace();
public void OnGPS()
final AlertDialog.Builder builder = new AlertDialog.Builder(mContext);
builder.setMessage("Enable GPS").setCancelable(false).setPositiveButton("YES", new DialogInterface.OnClickListener()
@Override
public void onClick(DialogInterface dialog, int which)
mContext.startActivity(new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS));
).setNegativeButton("NO", new DialogInterface.OnClickListener()
@Override
public void onClick(DialogInterface dialog, int which)
dialog.cancel();
);
final AlertDialog alertDialog = builder.create();
alertDialog.show();
【讨论】:
如何通过点击“是”而不是重定向用户进行配置来启用 GPS? 当你点击是按钮时:mContext.startActivity(new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS));将触发显式意图以启用 GPS。 @AlitonOliveira【参考方案6】:实际上我们可以使用这两个提供商(GPS 和 NETWORK)。他们只是共享一个公共听众:
locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 10 * 1000, (float) 10.0, listener);
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 90 * 1000, (float) 10.0, listener);
这是必要的,因为OnLocationChanged()
方法总是需要及时调用。
【讨论】:
【参考方案7】:@Fedor Greate 的 Kotlin 版本回答:
类的用法:
val locationResult = object : MyLocation.LocationResult()
override fun gotLocation(location: Location?)
val lat = location!!.latitude
val lon = location.longitude
Toast.makeText(context, "$lat --SLocRes-- $lon", Toast.LENGTH_SHORT).show()
val myLocation = MyLocation()
myLocation.getLocation(inflater.context, locationResult)
MyLocation
类:
class MyLocation
internal lateinit var timer1: Timer
internal var lm: LocationManager? = null
internal lateinit var locationResult: LocationResult
internal var gps_enabled = false
internal var network_enabled = false
internal var locationListenerGps: LocationListener = object : LocationListener
override fun onLocationChanged(location: Location)
timer1.cancel()
locationResult.gotLocation(location)
lm!!.removeUpdates(this)
lm!!.removeUpdates(locationListenerNetwork)
override fun onProviderDisabled(provider: String)
override fun onProviderEnabled(provider: String)
override fun onStatusChanged(provider: String, status: Int, extras: Bundle)
internal var locationListenerNetwork: LocationListener = object : LocationListener
override fun onLocationChanged(location: Location)
timer1.cancel()
locationResult.gotLocation(location)
lm!!.removeUpdates(this)
lm!!.removeUpdates(locationListenerGps)
override fun onProviderDisabled(provider: String)
override fun onProviderEnabled(provider: String)
override fun onStatusChanged(provider: String, status: Int, extras: Bundle)
fun getLocation(context: Context, result: LocationResult): Boolean
//I use LocationResult callback class to pass location value from MyLocation to user code.
locationResult = result
if (lm == null)
lm = context.getSystemService(Context.LOCATION_SERVICE) as LocationManager?
//exceptions will be thrown if provider is not permitted.
try
gps_enabled = lm!!.isProviderEnabled(LocationManager.GPS_PROVIDER)
catch (ex: Exception)
try
network_enabled = lm!!.isProviderEnabled(LocationManager.NETWORK_PROVIDER)
catch (ex: Exception)
//don't start listeners if no provider is enabled
if (!gps_enabled && !network_enabled)
return false
if (ActivityCompat.checkSelfPermission(context,
Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED ||
ActivityCompat.checkSelfPermission(context, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) run
ActivityCompat.requestPermissions(context as Activity,
arrayOf(Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION), 111)
if (gps_enabled)
lm!!.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0f, locationListenerGps)
if (network_enabled)
lm!!.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0f, locationListenerNetwork)
timer1 = Timer()
timer1.schedule(GetLastLocation(context), 20000)
return true
internal inner class GetLastLocation(var context: Context) : TimerTask()
override fun run()
lm!!.removeUpdates(locationListenerGps)
lm!!.removeUpdates(locationListenerNetwork)
var net_loc: Location? = null
var gps_loc: Location? = null
if (ActivityCompat.checkSelfPermission(context,
Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED ||
ActivityCompat.checkSelfPermission(context, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED
) run
ActivityCompat.requestPermissions(context as Activity,
arrayOf(Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION),111)
if (gps_enabled)
gps_loc = lm!!.getLastKnownLocation(LocationManager.GPS_PROVIDER)
if (network_enabled)
net_loc = lm!!.getLastKnownLocation(LocationManager.NETWORK_PROVIDER)
//if there are both values use the latest one
if (gps_loc != null && net_loc != null)
if (gps_loc.getTime() > net_loc.getTime())
locationResult.gotLocation(gps_loc)
else
locationResult.gotLocation(net_loc)
return
if (gps_loc != null)
locationResult.gotLocation(gps_loc)
return
if (net_loc != null)
locationResult.gotLocation(net_loc)
return
locationResult.gotLocation(null)
abstract class LocationResult
abstract fun gotLocation(location: Location?)
【讨论】:
【参考方案8】:从过去一年多开始,我一直在使用 GPS_PROVIDER 和 NETWORK_PROVIDER 的组合来获取当前位置,并且效果很好,但是从最近几个月开始,我在长时间延迟后才获得位置,所以我切换到了最新的API FusedLocationProviderClient,它工作得很好。
这是我编写的使用 FusedLocationProviderClient 获取当前位置的类。 在下面的代码中,我使用了一个定时器来等待获取当前位置,我将定时器设置为延迟 15 秒,你可以根据你的需要更改它。
private static FusedLocationService ourInstance;
private final LocationRequest locationRequest;
private FusedLocationProviderClient mFusedLocationClient;
private Location mLastLocation;
private Context context;
private FindOutLocation findOutLocation;
private boolean callbackTriggered = false;
private Timer timer;
public static FusedLocationService getInstance(Context pContext)
if (null == ourInstance) ourInstance = new FusedLocationService(pContext);
return ourInstance;
private FusedLocationService(Context pContext)
context = pContext;
mFusedLocationClient = LocationServices.getFusedLocationProviderClient(context);
locationRequest = getLocationRequest();
requestLocation(context);
public Location getLastKnownLocation()
return mLastLocation;
private void requestLocation(Context context)
if (ActivityCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(context, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED)
return;
mFusedLocationClient.requestLocationUpdates(locationRequest, mLocationCallback, null);
mFusedLocationClient.getLastLocation().addOnSuccessListener(location ->
if (location != null)
mLastLocation = location;
triggerCallback(mLastLocation);
);
private LocationRequest getLocationRequest()
LocationRequest locationRequest = new LocationRequest();
long INTERVAL = 10 * 1000;
long FASTEST_INTERVAL = 5 * 1000;
locationRequest.setInterval(INTERVAL);
locationRequest.setFastestInterval(FASTEST_INTERVAL);
locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
return locationRequest;
private LocationCallback mLocationCallback = new LocationCallback()
@Override
public void onLocationResult(LocationResult locationResult)
for (Location location : locationResult.getLocations())
if (location != null) mLastLocation = location;
if (null != mLastLocation) triggerCallback(mLastLocation);
;
public static abstract class FindOutLocation
public abstract void gotLocation(Location location);
@SuppressLint("MissingPermission")
public void findLocation(FindOutLocation findOutLocation)
long TIMER_TIME_OUT = 15 * 1000;
this.findOutLocation = findOutLocation;
callbackTriggered = false;
try
requestLocation(context);
timer = new Timer();
timer.schedule(new GetLastLocation(context), TIMER_TIME_OUT);
catch (Exception e)
e.printStackTrace();
private class GetLastLocation extends TimerTask
Context context;
GetLastLocation(Context context)
this.context = context;
@Override
public void run()
triggerCallback(mLastLocation);
private void triggerCallback(Location location)
if (null != location) mLastLocation = location;
if (!callbackTriggered && null != findOutLocation)
callbackTriggered = true;
removeLocationUpdates();
findOutLocation.gotLocation(location);
findOutLocation = null;
private void removeLocationUpdates()
if (null != timer) timer.cancel();
if (null != mFusedLocationClient)
mFusedLocationClient.removeLocationUpdates(mLocationCallback);
并从活动中调用它,这是代码
FusedLocationService.FindOutLocation findOutLocation = new FusedLocationService.FindOutLocation()
@Override
public void gotLocation(Location currentLocation)
if (currentLocation != null)
/*TODO DO SOMETHING WITH CURRENT LOCATION*/
;
FusedLocationService.getInstance(this).findLocation(findOutLocation);
在 AndroidManifest.xml 中添加以下条目
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<!-- Needed only if your app targets Android 5.0 (API level 21) or higher. -->
<uses-feature android:name="android.hardware.location.gps" />
【讨论】:
【参考方案9】:查看所有答案和问题后(最简单和最强大)。我只点击了库Android-ReactiveLocation。
当我制作了一个位置跟踪应用程序时。然后我意识到通过电池优化来处理位置跟踪是非常典型的。
所以我想告诉那些不想在未来优化时维护他们的位置代码的新手和开发人员。使用这个库。
ReactiveLocationProvider locationProvider = new
ReactiveLocationProvider(context);
locationProvider.getLastKnownLocation()
.subscribe(new Consumer<Location>()
@Override
public void call(Location location)
doSthImportantWithObtainedLocation(location);
);
要放入应用级 build.gradle 的依赖项
dependencies
...
compile 'pl.charmas.android:android-reactive-location2:2.1@aar'
compile 'com.google.android.gms:play-services-location:11.0.4' //you can use newer GMS version if you need
compile 'com.google.android.gms:play-services-places:11.0.4'
compile 'io.reactivex:rxjava:2.0.5' //you can override RxJava version if you need
使用此库的优点:
这个库是并将积极维护。 您不必担心电池优化。开发人员已经尽了最大努力。 安装简单,放依赖即可玩。 轻松连接到 Play Services API 获取最后一个已知位置 订阅位置更新使用 位置设置 API 管理地理围栏 地址列表的地理编码位置 活动识别 使用当前位置 API 获取位置 自动完成建议【讨论】:
【参考方案10】:这是我请求用户权限的方式。
在 AndroidManifest.xml 中的应用程序标签之外添加这些权限请求。
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
然后在 App Gradle 文件中添加 Google 的 Location 依赖项。
implementation 'com.google.android.gms:play-services-location:15.0.0'
现在声明一些全局变量。
private lateinit var mFusedLocationProvider:FusedLocationProviderClient
private lateinit var mLocationCallback: LocationCallback
private lateinit var mLocationRequest: LocationRequest
private var mLocationPermissionGranted:Boolean = false
在您的 Activity 的 OnCreate 方法中(我无法正确格式化代码,对此深表歉意)
mFusedLocationProvider = LocationServices.getFusedLocationProviderClient(this)
//Location Callback
mLocationCallback = object: LocationCallback()
override fun onLocationResult(p0: LocationResult?)
if(p0==null)
//todo(request user to enable location from settings then remove return)
return
else
getDeviceLocation()
//Location Request
mLocationRequest = LocationRequest.create()
mLocationRequest.priority = LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY
//Set the Interval for Latest Interval Update
mLocationRequest.interval = 5000
//Set How Many Location Updated you Want
mLocationRequest.numUpdates = 1
getLocationPermission()
getDeviceLocation()
现在创建这两个函数。
private fun getLocationPermission()
val permission:Array<String> = arrayOf(android.Manifest.permission.ACCESS_FINE_LOCATION,android.Manifest.permission.ACCESS_COARSE_LOCATION)
if(ContextCompat.checkSelfPermission(applicationContext,Constant.FINE_LOCATION)== PermissionChecker.PERMISSION_GRANTED)
if(ContextCompat.checkSelfPermission(applicationContext,Constant.COARSE_LOCATION)== PermissionChecker.PERMISSION_GRANTED)
mLocationPermissionGranted = true
else
ActivityCompat.requestPermissions(this,permission,Constant.LOCATION_REQUEST_CODE)
第二种方法
private fun getDeviceLocation()
try
if(mLocationPermissionGranted)
mFusedLocationProvider.lastLocation.addOnCompleteListener(this,task: Task<Location> ->
if(task.isSuccessful)
var currentLocation: Location? = task.result
if(currentLocation!=null)
Log.i("Location","Latitude is $currentLocation.latitude and Longitude" +
"$currentLocation.longitude")
else
mFusedLocationProvider.requestLocationUpdates(mLocationRequest,mLocationCallback,null)
)
catch (e:SecurityException)
Log.e("Error", "Security Exception $e.message")
对于常量.kt
class Constant
companion object
//Location Request Settings
const val SET_INTERVAL:Long = 2000
const val NUM_UPDATES:Int = 1
//Location Permission
const val FINE_LOCATION:String = android.Manifest.permission.ACCESS_FINE_LOCATION
const val COARSE_LOCATION:String = android.Manifest.permission.ACCESS_COARSE_LOCATION
【讨论】:
【参考方案11】:最近重构获取代码的位置,学习了一些好的思路,终于实现了一个比较完善的库和Demo。
//request all valid provider(network/gps)
private boolean requestAllProviderUpdates()
checkRuntimeEnvironment();
checkPermission();
if (isRequesting)
EasyLog.d("Request location update is busy");
return false;
long minTime = getCheckTimeInterval();
float minDistance = getCheckMinDistance();
if (mMapLocationListeners == null)
mMapLocationListeners = new HashMap<>();
mValidProviders = getValidProviders();
if (mValidProviders == null || mValidProviders.isEmpty())
throw new IllegalArgumentException("Not available provider.");
for (String provider : mValidProviders)
LocationListener locationListener = new LocationListener()
@Override
public void onLocationChanged(Location location)
if (location == null)
EasyLog.e("LocationListener callback location is null.");
return;
printf(location);
mLastProviderTimestamp = location.getTime();
if (location.getProvider().equals(LocationManager.GPS_PROVIDER))
finishResult(location);
else
doLocationResult(location);
removeProvider(location.getProvider());
if (isEmptyValidProviders())
requestTimeoutMsgInit();
removeUpdates();
@Override
public void onStatusChanged(String provider, int status, Bundle extras)
@Override
public void onProviderEnabled(String provider)
@Override
public void onProviderDisabled(String provider)
;
getLocationManager().requestLocationUpdates(provider, minTime, minDistance, locationListener);
mMapLocationListeners.put(provider, locationListener);
EasyLog.d("Location request %s provider update.", provider);
isRequesting = true;
return true;
//remove request update
public void removeUpdates()
checkRuntimeEnvironment();
LocationManager locationManager = getLocationManager();
if (mMapLocationListeners != null)
Set<String> keys = mMapLocationListeners.keySet();
for (String key : keys)
LocationListener locationListener = mMapLocationListeners.get(key);
if (locationListener != null)
locationManager.removeUpdates(locationListener);
EasyLog.d("Remove location update, provider is " + key);
mMapLocationListeners.clear();
isRequesting = false;
//Compared with the last successful position, to determine whether you need to filter
private boolean isNeedFilter(Location location)
checkLocation(location);
if (mLastLocation != null)
float distance = location.distanceTo(mLastLocation);
if (distance < getCheckMinDistance())
return true;
if (location.getAccuracy() >= mLastLocation.getAccuracy()
&& distance < location.getAccuracy())
return true;
if (location.getTime() <= mLastProviderTimestamp)
return true;
return false;
private void doLocationResult(Location location)
checkLocation(location);
if (isNeedFilter(location))
EasyLog.d("location need to filtered out, timestamp is " + location.getTime());
finishResult(mLastLocation);
else
finishResult(location);
//Return to the finished position
private void finishResult(Location location)
checkLocation(location);
double latitude = location.getLatitude();
double longitude = location.getLongitude();
float accuracy = location.getAccuracy();
long time = location.getTime();
String provider = location.getProvider();
if (mLocationResultListeners != null && !mLocationResultListeners.isEmpty())
String format = "Location result:<%f, %f> Accuracy:%f Time:%d Provider:%s";
EasyLog.i(String.format(format, latitude, longitude, accuracy, time, provider));
mLastLocation = location;
synchronized (this)
Iterator<LocationResultListener> iterator = mLocationResultListeners.iterator();
while (iterator.hasNext())
LocationResultListener listener = iterator.next();
if (listener != null)
listener.onResult(location);
iterator.remove();
完整代码:https://github.com/bingerz/FastLocation/blob/master/fastlocationlib/src/main/java/cn/bingerz/fastlocation/FastLocation.java
*每次请求完成定位,最好去掉Updates,否则手机状态栏会一直显示定位图标。
【讨论】:
【参考方案12】:我已经在demonuts.com 上写了涵盖current location 的详细教程。您可以在此处找到更多描述,也可以下载整个演示源代码以更好地理解。
那里已经有很多答案,但我想展示使用 Google API 获取位置的最新方法,以便新程序员可以使用新方法:
首先,把这个放到gradle文件中
compile 'com.google.android.gms:play-services:8.4.0'
然后实现必要的接口
public class MainActivity extends BaseActivitiy implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener, com.google.android.gms.location.LocationListener
声明实例
private GoogleApiClient mGoogleApiClient;
private Location mLocation;
private LocationManager locationManager;
private LocationRequest mLocationRequest;
把这个放到onCreate()
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
最后,重写必要的方法
@Override
public void onConnected(Bundle bundle)
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;
mLocation = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
if(mLocation == null)
startLocationUpdates();
if (mLocation != null)
double latitude = mLocation.getLatitude();
double longitude = mLocation.getLongitude();
else
// Toast.makeText(this, "Location not Detected", Toast.LENGTH_SHORT).show();
protected void startLocationUpdates()
// Create the location request
mLocationRequest = LocationRequest.create()
.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY)
.setInterval(UPDATE_INTERVAL)
.setFastestInterval(FASTEST_INTERVAL);
// Request location updates
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;
LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient,
mLocationRequest, this);
Log.d("reque", "--->>>>");
@Override
public void onConnectionSuspended(int i)
Log.i(TAG, "Connection Suspended");
mGoogleApiClient.connect();
@Override
public void onConnectionFailed(ConnectionResult connectionResult)
Log.i(TAG, "Connection failed. Error: " + connectionResult.getErrorCode());
@Override
public void onStart()
super.onStart();
mGoogleApiClient.connect();
@Override
public void onStop()
super.onStop();
if (mGoogleApiClient.isConnected())
mGoogleApiClient.disconnect();
@Override
public void onLocationChanged(Location location)
在运行应用程序之前,不要忘记在您的设备中启动 GPS。
【讨论】:
使用 API 吗?所以这是服务是速率限制的权利。【参考方案13】:这是我的工作:
-
首先我检查是否启用了 NETWORK 或 GPS 提供程序。有些可能在设备上被禁用,有些可能在应用程序清单中被禁用。如果启用了任何提供程序,我会为此提供程序获取缓存的最后一个位置,并为此提供程序启动位置更新侦听器。
有一种方法可以确定位置是否比链接中提到的上次接收到的位置更好:-https://developer.android.com/guide/topics/location/strategies.html#BestEstimate
如果我从位置侦听器获得更新,我会检查此位置是否比之前收到的位置更好。如果它比将这个位置替换为以前的最佳位置更好(
mFinalLocation
)。
还有一个处理程序(计时器)两分钟,最终停止服务,并在onDestroy()
服务方法中,停止侦听每个提供者的位置更新。
以下是服务代码。您可以根据需要的位置更新频率运行它。
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.support.annotation.Nullable;
import android.util.Log;
public class RecordLocationService extends Service
private final String TAG = RecordLocationService.class.getSimpleName();
private final int TWO_MINUTES = 1000 * 60 * 2;
private LocationManager mLocationManager;
private MyLocationListener mLocationListeners[] = new MyLocationListener[]
new MyLocationListener(LocationManager.NETWORK_PROVIDER),
new MyLocationListener(LocationManager.GPS_PROVIDER)
;
private Location mFinalLocation;
private class MyLocationListener implements LocationListener
private String mProvider;
public MyLocationListener(String provider)
Log.d(TAG, "LocationListener : " + provider);
mProvider = provider;
public String getProvider()
return mProvider;
@Override
public void onLocationChanged(Location location)
Log.d(TAG, "onLocationChanged : " + location);
if (isBetterLocation(location, mFinalLocation))
Log.d(TAG, "Setting current Final Location to recent most Location for Provider : " + location.getProvider());
Log.d(TAG, "Setting current Final Location to : " + location);
mFinalLocation = location;
else
Log.d(TAG, "Keeping current Final Location to previous Final Location");
@Override
public void onStatusChanged(String provider, int status, Bundle extras)
Log.d(TAG, "onStatusChanged provider " + provider);
@Override
public void onProviderEnabled(String provider)
Log.d(TAG, "onProviderEnabled provider " + provider);
@Override
public void onProviderDisabled(String provider)
Log.d(TAG, "onProviderDisabled provider " + provider);
private Handler mStopServiceHandler = new Handler()
@Override
public void handleMessage(Message msg)
switch (msg.what)
case 1:
stopSelf();
break;
;
@Nullable
@Override
public IBinder onBind(Intent intent)
return null;
@Override
public int onStartCommand(Intent intent, int flags, int startId)
super.onStartCommand(intent, flags, startId);
Log.d(TAG, "onStartCommand");
return START_STICKY;
@Override
public void onCreate()
super.onCreate();
Log.d(TAG, "onCreate");
requestLocation();
mStopServiceHandler.sendEmptyMessageDelayed(1, TWO_MINUTES);
private void requestLocation()
// Acquire a reference to the system Location Manager
if (mLocationManager == null)
mLocationManager = (LocationManager) this.getApplicationContext().getSystemService(Context.LOCATION_SERVICE);
try
if (mLocationManager.getAllProviders().contains(LocationManager.NETWORK_PROVIDER) && mLocationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER))
Log.d(TAG, "Fetching Cached Location for Provider : " + LocationManager.NETWORK_PROVIDER);
Location cachedNetworkLocation = mLocationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
if (cachedNetworkLocation != null)
Log.d(TAG, "Setting Final Location to Cached Location for Provider : " + LocationManager.NETWORK_PROVIDER);
Log.d(TAG, "Setting Final Location to : " + cachedNetworkLocation);
mFinalLocation = cachedNetworkLocation;
else
Log.d(TAG, "Cached Location for Provider : " + LocationManager.NETWORK_PROVIDER + " is NULL");
Log.d(TAG, "Requesting Location Update for Provider : " + LocationManager.NETWORK_PROVIDER);
mLocationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, mLocationListeners[0]);
catch (SecurityException se)
Log.e(TAG, se.getMessage(), se);
catch (IllegalArgumentException iae)
Log.e(TAG, iae.getMessage(), iae);
try
if (mLocationManager.getAllProviders().contains(LocationManager.GPS_PROVIDER) && mLocationManager.isProviderEnabled(LocationManager.GPS_PROVIDER))
Log.d(TAG, "Fetching Cached Location for Provider : " + LocationManager.GPS_PROVIDER);
Location cachedGPSLocation = mLocationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
if (cachedGPSLocation != null)
if (isBetterLocation(cachedGPSLocation, mFinalLocation))
Log.d(TAG, "Setting Final Location to Cached Location for Provider : " + LocationManager.GPS_PROVIDER);
Log.d(TAG, "Setting Final Location to : " + cachedGPSLocation);
mFinalLocation = cachedGPSLocation;
else
Log.d(TAG, "Cached Location for Provider : " + LocationManager.GPS_PROVIDER + " is NULL");
Log.d(TAG, "Requesting Location Update for Provider : " + LocationManager.GPS_PROVIDER);
mLocationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, mLocationListeners[1]);
catch (SecurityException se)
Log.e(TAG, se.getMessage(), se);
catch (IllegalArgumentException iae)
Log.e(TAG, iae.getMessage(), iae);
/**
* Determines whether one Location reading is better than the current Location fix
*
* @param location The new Location that you want to evaluate
* @param currentBestLocation The current Location fix, to which you want to compare the new one
*/
protected boolean isBetterLocation(Location location, Location currentBestLocation)
if (currentBestLocation == null)
// A new location is always better than no location
return true;
// Check whether the new location fix is newer or older
long timeDelta = location.getTime() - currentBestLocation.getTime();
boolean isSignificantlyNewer = timeDelta > TWO_MINUTES;
boolean isSignificantlyOlder = timeDelta < -TWO_MINUTES;
boolean isNewer = timeDelta > 0;
// If it's been more than two minutes since the current location, use the new location
// because the user has likely moved
if (isSignificantlyNewer)
return true;
// If the new location is more than two minutes older, it must be worse
else if (isSignificantlyOlder)
return false;
// Check whether the new location fix is more or less accurate
int accuracyDelta = (int) (location.getAccuracy() - currentBestLocation.getAccuracy());
boolean isLessAccurate = accuracyDelta > 0;
boolean isMoreAccurate = accuracyDelta < 0;
boolean isSignificantlyLessAccurate = accuracyDelta > 200;
// Check if the old and new location are from the same provider
boolean isFromSameProvider = isSameProvider(location.getProvider(),
currentBestLocation.getProvider());
// Determine location quality using a combination of timeliness and accuracy
if (isMoreAccurate)
return true;
else if (isNewer && !isLessAccurate)
return true;
else if (isNewer && !isSignificantlyLessAccurate && isFromSameProvider)
return true;
return false;
/**
* Checks whether two providers are the same
*/
private boolean isSameProvider(String provider1, String provider2)
if (provider1 == null)
return provider2 == null;
return provider1.equals(provider2);
@Override
public void onDestroy()
super.onDestroy();
Log.d(TAG, "onDestroy");
if (mLocationManager != null)
for (int i = 0; i < mLocationListeners.length; i++)
try
Log.d(TAG, "Removing Location Update for Provider : " + mLocationListeners[i].getProvider());
mLocationManager.removeUpdates(mLocationListeners[i]);
catch (Exception ex)
Log.e(TAG, "fail to remove location listeners, ignore", ex);
【讨论】:
【参考方案14】:您总是可以只使用LocationManager.getLastKnownLocation(),但就像它所说的那样,它可能已经过时了。
获取大致位置的一种简单方法是注册网络(通常非常快)。
LocationManager locationManager = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE);
locationManager.requestLocationUpdates(
LocationManager.NETWORK_PROVIDER, 1000, 1000, this);
然后做
locationManager.removeUpdates(this);
在监听器的onLocationChanged()
方法中。
【讨论】:
感谢 BrennaSoft。我发现 getLastKnownLocation() 经常会被严重关闭,因此不能真正作为独立的解决方案工作。另外,我不清楚仅依靠 NETWORK_PROVIDER 是否可行,因为该国许多地区没有很好的 wifi 接入点 GPS 坐标(而且我不知道手机信号塔)【参考方案15】:在 android 中获取位置更新需要做很多事情, 需要大量的样板代码。
你需要照顾
Google Play 服务可用性检查, 如果 Google Play 服务过时或不可用,请更新它 GoogleApiClient 的对话框创建及其回调连接、断开等。 停止和释放用于位置更新的资源 处理位置权限场景 检查位置服务是打开还是关闭 获取最后一个已知位置也不是那么容易 如果在一定时间后没有获得位置,则回退到最后一个已知位置我创建了Android-EasyLocation (small android library),它将处理所有这些事情,您可以专注于业务逻辑。
您只需要扩展 EasyLocationActivity 和这个
requestSingleLocationFix(easyLocationRequest);
或
requestLocationUpdates(easyLocationRequest);
在https://github.com/akhgupta/Android-EasyLocation查看所需的示例应用程序和步骤
【讨论】:
【参考方案16】:通过使用 FusedLocationProviderApi,它是最新的 API,也是在 Android 中获取位置的可用可能性中最好的。 在 build.gradle 文件中添加这个
dependencies
compile 'com.google.android.gms:play-services:6.5.87'
你可以通过这个网址获得完整的源代码 http://javapapers.com/android/android-location-fused-provider/
【讨论】:
【参考方案17】:使用下面的代码,它将提供最好的提供者:
String locCtx = Context.LOCATION_SERVICE;
LocationManager locationMgr = (LocationManager) ctx.getSystemService(locCtx);
Criteria criteria = new Criteria();
criteria.setAccuracy(Criteria.ACCURACY_FINE);
criteria.setAltitudeRequired(false);
criteria.setBearingRequired(false);
criteria.setCostAllowed(true);
criteria.setPowerRequirement(Criteria.POWER_LOW);
String provider = locationMgr.getBestProvider(criteria, true);
System.out.println("Best Available provider::::"+provider);
【讨论】:
如何初始化ctx, Context ctx= this; ?它崩溃了【参考方案18】:即使这里已经给出了答案。我只是想把这个分享给全世界,以防遇到这种情况。
我的要求是我需要在最多 30 到 35 秒内获得用户的当前位置,所以这是我在 Nirav Ranpara's Answer 之后提出的解决方案。
1. 我创建了 MyLocationManager.java 类来处理所有 GPS 和网络的东西
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import com.app.callbacks.OnLocationDetectectionListener;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.provider.Settings;
import android.util.Log;
import android.widget.Toast;
public class MyLocationManager
/** The minimum distance to GPS change Updates in meters **/
private final long MIN_DISTANCE_CHANGE_FOR_UPDATES_FOR_GPS = 2; // 2
// meters
/** The minimum time between GPS updates in milliseconds **/
private final long MIN_TIME_BW_UPDATES_OF_GPS = 1000 * 5 * 1; // 5
// seconds
/** The minimum distance to NETWORK change Updates in meters **/
private final long MIN_DISTANCE_CHANGE_FOR_UPDATES_FOR_NETWORK = 5; // 5
// meters
/** The minimum time between NETWORK updates in milliseconds **/
private final long MIN_TIME_BW_UPDATES_OF_NETWORK = 1000 * 10 * 1; // 10
// seconds
/**
* Lets just say i don't trust the first location that the is found. This is
* to avoid that
**/
private int NetworkLocationCount = 0, GPSLocationCount = 0;
private boolean isGPSEnabled;
private boolean isNetworkEnabled;
/**
* Don't do anything if location is being updated by Network or by GPS
*/
private boolean isLocationManagerBusy;
private LocationManager locationManager;
private Location currentLocation;
private Context mContext;
private OnLocationDetectectionListener mListener;
public MyLocationManager(Context mContext,
OnLocationDetectectionListener mListener)
this.mContext = mContext;
this.mListener = mListener;
/**
* Start the location manager to find my location
*/
public void startLocating()
try
locationManager = (LocationManager) mContext
.getSystemService(Context.LOCATION_SERVICE);
// Getting GPS status
isGPSEnabled = locationManager
.isProviderEnabled(LocationManager.GPS_PROVIDER);
// Getting network status
isNetworkEnabled = locationManager
.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
if (!isGPSEnabled && !isNetworkEnabled)
// No network provider is enabled
showSettingsAlertDialog();
else
// If GPS enabled, get latitude/longitude using GPS Services
if (isGPSEnabled)
locationManager.requestLocationUpdates(
LocationManager.GPS_PROVIDER,
MIN_TIME_BW_UPDATES_OF_GPS,
MIN_DISTANCE_CHANGE_FOR_UPDATES_FOR_GPS,
gpsLocationListener);
if (isNetworkEnabled)
locationManager.requestLocationUpdates(
LocationManager.NETWORK_PROVIDER,
MIN_TIME_BW_UPDATES_OF_NETWORK,
MIN_DISTANCE_CHANGE_FOR_UPDATES_FOR_NETWORK,
networkLocationListener);
/**
* My 30 seconds plan to get myself a location
*/
ScheduledExecutorService se = Executors
.newSingleThreadScheduledExecutor();
se.schedule(new Runnable()
@Override
public void run()
if (currentLocation == null)
if (isGPSEnabled)
currentLocation = locationManager
.getLastKnownLocation(LocationManager.GPS_PROVIDER);
else if (isNetworkEnabled)
currentLocation = locationManager
.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
if (currentLocation != null && mListener != null)
locationManager.removeUpdates(gpsLocationListener);
locationManager
.removeUpdates(networkLocationListener);
mListener.onLocationDetected(currentLocation);
, 30, TimeUnit.SECONDS);
catch (Exception e)
Log.e("Error Fetching Location", e.getMessage());
Toast.makeText(mContext,
"Error Fetching Location" + e.getMessage(),
Toast.LENGTH_SHORT).show();
/**
* Handle GPS location listener callbacks
*/
private LocationListener gpsLocationListener = new LocationListener()
@Override
public void onStatusChanged(String provider, int status, Bundle extras)
// TODO Auto-generated method stub
@Override
public void onProviderEnabled(String provider)
// TODO Auto-generated method stub
@Override
public void onProviderDisabled(String provider)
// TODO Auto-generated method stub
@Override
public void onLocationChanged(Location location)
if (GPSLocationCount != 0 && !isLocationManagerBusy)
Log.d("GPS Enabled", "GPS Enabled");
isLocationManagerBusy = true;
currentLocation = location;
locationManager.removeUpdates(gpsLocationListener);
locationManager.removeUpdates(networkLocationListener);
isLocationManagerBusy = false;
if (currentLocation != null && mListener != null)
mListener.onLocationDetected(currentLocation);
GPSLocationCount++;
;
/**
* Handle Network location listener callbacks
*/
private LocationListener networkLocationListener = new LocationListener()
@Override
public void onStatusChanged(String provider, int status, Bundle extras)
// TODO Auto-generated method stub
@Override
public void onProviderEnabled(String provider)
// TODO Auto-generated method stub
@Override
public void onProviderDisabled(String provider)
// TODO Auto-generated method stub
@Override
public void onLocationChanged(Location location)
if (NetworkLocationCount != 0 && !isLocationManagerBusy)
Log.d("Network", "Network");
isLocationManagerBusy = true;
currentLocation = location;
locationManager.removeUpdates(gpsLocationListener);
locationManager.removeUpdates(networkLocationListener);
isLocationManagerBusy = false;
if (currentLocation != null && mListener != null)
mListener.onLocationDetected(currentLocation);
NetworkLocationCount++;
;
/**
* Function to show settings alert dialog. On pressing the Settings button
* it will launch Settings Options.
* */
public void showSettingsAlertDialog()
AlertDialog.Builder alertDialog = new AlertDialog.Builder(mContext);
// Setting Dialog Title
alertDialog.setTitle("GPS is settings");
// Setting Dialog Message
alertDialog
.setMessage("GPS is not enabled. Do you want to go to settings menu?");
// On pressing the Settings button.
alertDialog.setPositiveButton("Settings",
new DialogInterface.OnClickListener()
@Override
public void onClick(DialogInterface dialog, int which)
Intent intent = new Intent(
Settings.ACTION_LOCATION_SOURCE_SETTINGS);
mContext.startActivity(intent);
);
// On pressing the cancel button
alertDialog.setNegativeButton("Cancel",
new DialogInterface.OnClickListener()
@Override
public void onClick(DialogInterface dialog, int which)
dialog.cancel();
);
// Showing Alert Message
alertDialog.show();
2.我创建了一个接口(回调)OnLocationDetectectionListener.java,以便将结果传达回调用片段或活动
import android.location.Location;
public interface OnLocationDetectectionListener
public void onLocationDetected(Location mLocation);
3. 然后我创建了一个实现OnLocationDetectectionListener
接口的MainAppActivty.java Activity,这是我在其中接收我的位置的方式
public class MainAppActivty extends Activity implements
OnLocationDetectectionListener
private Location currentLocation;
private MyLocationManager mLocationManager;
@Override
protected void onCreate(Bundle savedInstanceState)
setContentView(R.layout.activity_home);
super.onCreate(savedInstanceState);
mLocationManager = new MyLocationManager(this, this);
mLocationManager.startLocating();
@Override
public void onLocationDetected(Location mLocation)
//Your new Location is received here
currentLocation = mLocation;
4.将以下权限添加到您的清单文件中
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
希望这对其他人有帮助:)
【讨论】:
【参考方案19】:这里有点晚了,但在这种情况下我会使用谷歌地图 API 并使用谷歌地图的经纬度 API 标记附近的位置。另外,如果您可以在地图上显示他/她的位置,用户体验会更好。无需担心用户位置的更新或使用 android api 搜身。让谷歌地图为您处理内部事务。
@emmby 可能已经在他的应用程序中解决了这个问题,但我建议其他开发者参考 Google 地图 API 以了解特定位置的内容。
编辑:显示user location in google maps的链接
【讨论】:
【参考方案20】:编辑:使用来自 Google Play 服务库的最新 Location Service API 进行了更新(2014 年 7 月)
我建议您使用新的Location Service API,它可以从 Google Play 服务库中获得,它提供了一个更强大的高级框架,可以自动执行位置提供程序选择和电源管理等任务。根据官方文档:“...... Location API 让您可以轻松构建位置感知应用程序,而无需关注底层定位技术的细节。它们还让您通过使用所有功能来最小化功耗设备硬件。”
欲了解更多信息,请访问:Making Your App Location-Aware
要查看使用最新位置服务 API 的完整示例,请访问:Android LocationClient class is deprecated but used in documentation
【讨论】:
【参考方案21】:推荐的方法是使用LocationClient
:
首先,定义位置更新间隔值。根据您的需要进行调整。
private static final int MILLISECONDS_PER_SECOND = 1000;
private static final long UPDATE_INTERVAL = MILLISECONDS_PER_SECOND * UPDATE_INTERVAL_IN_SECONDS;
private static final int FASTEST_INTERVAL_IN_SECONDS = 1;
private static final long FASTEST_INTERVAL = MILLISECONDS_PER_SECOND * FASTEST_INTERVAL_IN_SECONDS;
让您的Activity
实现GooglePlayServicesClient.ConnectionCallbacks
、GooglePlayServicesClient.OnConnectionFailedListener
和LocationListener
。
public class LocationActivity extends Activity implements
GooglePlayServicesClient.ConnectionCallbacks, GooglePlayServicesClient.OnConnectionFailedListener, LocationListener
然后,在你的Activity
的onCreate()
方法中设置一个LocationClient
:
public void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
mLocationClient = new LocationClient(this, this, this);
mLocationRequest = LocationRequest.create();
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
mLocationRequest.setInterval(UPDATE_INTERVAL);
mLocationRequest.setFastestInterval(FASTEST_INTERVAL);
将所需的方法添加到您的Activity
; onConnected()
是LocationClient
connect 时调用的方法。 onLocationChanged()
是您检索最新位置的位置。
@Override
public void onConnectionFailed(ConnectionResult connectionResult)
Log.w(TAG, "Location client connection failed");
@Override
public void onConnected(Bundle dataBundle)
Log.d(TAG, "Location client connected");
mLocationClient.requestLocationUpdates(mLocationRequest, this);
@Override
public void onDisconnected()
Log.d(TAG, "Location client disconnected");
@Override
public void onLocationChanged(Location location)
if (location != null)
Log.d(TAG, "Updated Location: " + Double.toString(location.getLatitude()) + "," + Double.toString(location.getLongitude()));
else
Log.d(TAG, "Updated location NULL");
确保连接/断开LocationClient
,这样它只会在绝对必要时使用额外的电池,因此 GPS 不会无限期地运行。必须连接LocationClient
才能从中获取数据。
public void onResume()
super.onResume();
mLocationClient.connect();
public void onStop()
if (mLocationClient.isConnected())
mLocationClient.removeLocationUpdates(this);
mLocationClient.disconnect();
super.onStop();
获取用户的位置。首先尝试使用LocationClient
;如果失败,请退回到LocationManager
。
public Location getLocation()
if (mLocationClient != null && mLocationClient.isConnected())
return mLocationClient.getLastLocation();
else
LocationManager locationManager = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE);
if (locationManager != null)
Location lastKnownLocationGPS = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
if (lastKnownLocationGPS != null)
return lastKnownLocationGPS;
else
return locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
else
return null;
【讨论】:
【参考方案22】:我创建了一个带有分步描述的小应用程序来获取当前位置 GPS 坐标。
以下网址中的完整示例源代码:
Get Current Location coordinates , City name - in Android
看看它是如何工作的:
我们需要做的就是在清单文件中添加这个权限
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION">
</uses-permission>
并像这样创建 LocationManager 实例
LocationManager locationManager = (LocationManager)
getSystemService(Context.LOCATION_SERVICE);
检查 GPS 是否启用
然后实现 LocationListener 并获取坐标
LocationListener locationListener = new MyLocationListener();
locationManager.requestLocationUpdates(
LocationManager.GPS_PROVIDER, 5000, 10, locationListener);
这里是示例代码
/*----------Listener class to get coordinates ------------- */
private class MyLocationListener implements LocationListener
@Override
public void onLocationChanged(Location loc)
editLocation.setText("");
pb.setVisibility(View.INVISIBLE);
Toast.makeText(
getBaseContext(),
"Location changed: Lat: " + loc.getLatitude() + " Lng: "
+ loc.getLongitude(), Toast.LENGTH_SHORT).show();
String longitude = "Longitude: " + loc.getLongitude();
Log.v(TAG, longitude);
String latitude = "Latitude: " + loc.getLatitude();
Log.v(TAG, latitude);
/*-------to get City-Name from coordinates -------- */
String cityName = null;
Geocoder gcd = new Geocoder(getBaseContext(), Locale.getDefault());
List<Address> addresses;
try
addresses = gcd.getFromLocation(loc.getLatitude(),
loc.getLongitude(), 1);
if (addresses.size() > 0)
System.out.println(addresses.get(0).getLocality());
cityName = addresses.get(0).getLocality();
catch (IOException e)
e.printStackTrace();
String s = longitude + "\n" + latitude + "\n\nMy Current City is: "
+ cityName;
editLocation.setText(s);
@Override
public void onProviderDisabled(String provider)
@Override
public void onProviderEnabled(String provider)
@Override
public void onStatusChanged(String provider, int status, Bundle extras)
【讨论】:
位置需要更改。不是站着。【参考方案23】:GeoLocation 的简单和最佳方式。
LocationManager lm = null;
boolean network_enabled;
if (lm == null)
lm = (LocationManager) Kikit.this.getSystemService(Context.LOCATION_SERVICE);
network_enabled = lm.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
dialog = ProgressDialog.show(Kikit.this, "", "Fetching location...", true);
final Handler handler = new Handler();
timer = new Timer();
TimerTask doAsynchronousTask = new TimerTask()
@Override
public void run()
handler.post(new Runnable()
@Override
public void run()
Log.e("counter value","value "+counter);
if(counter<=8)
try
counter++;
if (network_enabled)
lm = (LocationManager) Kikit.this.getSystemService(Context.LOCATION_SERVICE);
Log.e("in network_enabled..","in network_enabled");
// Define a listener that responds to location updates
LocationListener locationListener = new LocationListener()
public void onLocationChanged(Location location)
if(attempt == false)
attempt = true;
Log.e("in location listener..","in location listener..");
longi = location.getLongitude();
lati = location.getLatitude();
Data.longi = "" + longi;
Data.lati = "" + lati;
Log.e("longitude : ",""+longi);
Log.e("latitude : ",""+lati);
if(faceboo_name.equals(""))
if(dialog!=null)
dialog.cancel();
timer.cancel();
timer.purge();
Data.homepage_resume = true;
lm = null;
Intent intent = new Intent();
intent.setClass(Kikit.this,MainActivity.class);
startActivity(intent);
finish();
else
isInternetPresent = cd.isConnectingToInternet();
if (isInternetPresent)
if(dialog!=null)
dialog.cancel();
Showdata();
else
error_view.setText(Data.internet_error_msg);
error_view.setVisibility(0);
error_gone();
public void onStatusChanged(String provider, int status,
Bundle extras)
public void onProviderEnabled(String provider)
//Toast.makeText(getApplicationContext(), "Location enabled", Toast.LENGTH_LONG).show();
public void onProviderDisabled(String provider)
;
// Register the listener with the Location Manager to receive
// location updates
lm.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 100000, 10,locationListener);
else
//Toast.makeText(getApplicationContext(), "No Internet Connection.", 2000).show();
buildAlertMessageNoGps();
catch (Exception e)
// TODO
// Auto-generated
// catch
// block
else
timer.purge();
timer.cancel();
if(attempt == false)
attempt = true;
String locationProvider = LocationManager.NETWORK_PROVIDER;
// Or use LocationManager.GPS_PROVIDER
try
Location lastKnownLocation = lm.getLastKnownLocation(locationProvider);
longi = lastKnownLocation.getLongitude();
lati = lastKnownLocation.getLatitude();
Data.longi = "" + longi;
Data.lati = "" + lati;
catch (Exception e)
// TODO Auto-generated catch block
e.printStackTrace();
Log.i("exception in loc fetch", e.toString());
Log.e("longitude of last known location : ",""+longi);
Log.e("latitude of last known location : ",""+lati);
if(Data.fb_access_token == "")
if(dialog!=null)
dialog.cancel();
timer.cancel();
timer.purge();
Data.homepage_resume = true;
Intent intent = new Intent();
intent.setClass(Kikit.this,MainActivity.class);
startActivity(intent);
finish();
else
isInternetPresent = cd.isConnectingToInternet();
if (isInternetPresent)
if(dialog!=null)
dialog.cancel();
Showdata();
else
error_view.setText(Data.internet_error_msg);
error_view.setVisibility(0);
error_gone();
);
;
timer.schedule(doAsynchronousTask, 0, 2000);
private void buildAlertMessageNoGps()
final AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setMessage("Your WiFi & mobile network location is disabled , do you want to enable it?")
.setCancelable(false)
.setPositiveButton("Yes", new DialogInterface.OnClickListener()
public void onClick(@SuppressWarnings("unused") final DialogInterface dialog, @SuppressWarnings("unused") final int id)
startActivity(new Intent(android.provider.Settings.ACTION_LOCATION_SOURCE_SETTINGS));
setting_page = true;
)
.setNegativeButton("No", new DialogInterface.OnClickListener()
public void onClick(final DialogInterface dialog, @SuppressWarnings("unused") final int id)
dialog.cancel();
finish();
);
final AlertDialog alert = builder.create();
alert.show();
【讨论】:
【参考方案24】:这是提供用户当前位置的代码
创建地图活动:
public class Maps extends MapActivity
public static final String TAG = "MapActivity";
private MapView mapView;
private LocationManager locationManager;
Geocoder geocoder;
Location location;
LocationListener locationListener;
CountDownTimer locationtimer;
MapController mapController;
MapOverlay mapOverlay = new MapOverlay();
@Override
protected void onCreate(Bundle icicle)
super.onCreate(icicle);
setContentView(R.layout.main);
initComponents();
mapView.setBuiltInZoomControls(true);
mapView.setSatellite(true);
mapView.setTraffic(true);
mapView.setStreetView(true);
mapController = mapView.getController();
mapController.setZoom(16);
locationManager = (LocationManager) getSystemService(LOCATION_SERVICE);
if (locationManager == null)
Toast.makeText(Maps.this, "Location Manager Not Available",
Toast.LENGTH_SHORT).show();
return;
location = locationManager
.getLastKnownLocation(LocationManager.GPS_PROVIDER);
if (location == null)
location = locationManager
.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
if (location != null)
double lat = location.getLatitude();
double lng = location.getLongitude();
Toast.makeText(Maps.this, "Location Are" + lat + ":" + lng,
Toast.LENGTH_SHORT).show();
GeoPoint point = new GeoPoint((int) (lat * 1E6), (int) (lng * 1E6));
mapController.animateTo(point, new Message());
mapOverlay.setPointToDraw(point);
List<Overlay> listOfOverlays = mapView.getOverlays();
listOfOverlays.clear();
listOfOverlays.add(mapOverlay);
locationListener = new LocationListener()
public void onStatusChanged(String arg0, int arg1, Bundle arg2)
public void onProviderEnabled(String arg0)
public void onProviderDisabled(String arg0)
public void onLocationChanged(Location l)
location = l;
locationManager.removeUpdates(this);
if (l.getLatitude() == 0 || l.getLongitude() == 0)
else
double lat = l.getLatitude();
double lng = l.getLongitude();
Toast.makeText(Maps.this, "Location Are" + lat + ":" + lng,
Toast.LENGTH_SHORT).show();
;
if (locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER))
locationManager.requestLocationUpdates(
LocationManager.GPS_PROVIDER, 1000, 10f, locationListener);
locationManager.requestLocationUpdates(
LocationManager.NETWORK_PROVIDER, 1000, 10f, locationListener);
locationtimer = new CountDownTimer(30000, 5000)
@Override
public void onTick(long millisUntilFinished)
if (location != null) locationtimer.cancel();
@Override
public void onFinish()
if (location == null)
;
locationtimer.start();
public MapView getMapView()
return this.mapView;
private void initComponents()
mapView = (MapView) findViewById(R.id.map_container);
ImageView ivhome = (ImageView) this.findViewById(R.id.imageView_home);
ivhome.setOnClickListener(new OnClickListener()
public void onClick(View arg0)
// TODO Auto-generated method stub
Intent intent = new Intent(Maps.this, GridViewContainer.class);
startActivity(intent);
finish();
);
@Override
protected boolean isRouteDisplayed()
return false;
class MapOverlay extends Overlay
private GeoPoint pointToDraw;
public void setPointToDraw(GeoPoint point)
pointToDraw = point;
public GeoPoint getPointToDraw()
return pointToDraw;
@Override
public boolean draw(Canvas canvas, MapView mapView, boolean shadow,
long when)
super.draw(canvas, mapView, shadow);
Point screenPts = new Point();
mapView.getProjection().toPixels(pointToDraw, screenPts);
Bitmap bmp = BitmapFactory.decodeResource(getResources(),
R.drawable.select_map);
canvas.drawBitmap(bmp, screenPts.x, screenPts.y - 24, null);
return true;
main.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_
android:layout_
android:background="@android:color/black"
android:orientation="vertical" >
<com.google.android.maps.MapView
android:id="@+id/map_container"
android:layout_
android:layout_
android:apiKey="yor api key"
android:clickable="true"
android:focusable="true" />
</LinearLayout>
并在清单中定义以下权限:
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
【讨论】:
【参考方案25】:public static Location getBestLocation(Context ctxt)
Location gpslocation = getLocationByProvider(
LocationManager.GPS_PROVIDER, ctxt);
Location networkLocation = getLocationByProvider(
LocationManager.NETWORK_PROVIDER, ctxt);
Location fetchedlocation = null;
// if we have only one location available, the choice is easy
if (gpslocation != null)
Log.i("New Location Receiver", "GPS Location available.");
fetchedlocation = gpslocation;
else
Log.i("New Location Receiver",
"No GPS Location available. Fetching Network location lat="
+ networkLocation.getLatitude() + " lon ="
+ networkLocation.getLongitude());
fetchedlocation = networkLocation;
return fetchedlocation;
/**
* get the last known location from a specific provider (network/gps)
*/
private static Location getLocationByProvider(String provider, Context ctxt)
Location location = null;
// if (!isProviderSupported(provider))
// return null;
//
LocationManager locationManager = (LocationManager) ctxt
.getSystemService(Context.LOCATION_SERVICE);
try
if (locationManager.isProviderEnabled(provider))
location = locationManager.getLastKnownLocation(provider);
catch (IllegalArgumentException e)
Log.i("New Location Receiver", "Cannot access Provider " + provider);
return location;
【讨论】:
【参考方案26】:这是我的工作:
-
首先我检查启用了哪些提供程序。有些可能在设备上被禁用,有些可能在应用程序清单中被禁用。
如果有可用的提供程序,我将启动位置侦听器和超时计时器。在我的例子中是 20 秒,对于 GPS 来说可能不够,所以你可以放大它。
如果我从位置侦听器获取更新,我将使用提供的值。我停止监听器和计时器。
如果我没有收到任何更新并且计时器已过,我必须使用最后一个已知值。
我从可用的提供程序中获取最后一个已知值并选择其中最新的。
这是我使用班级的方式:
LocationResult locationResult = new LocationResult()
@Override
public void gotLocation(Location location)
//Got the location!
;
MyLocation myLocation = new MyLocation();
myLocation.getLocation(this, locationResult);
这是 MyLocation 类:
import java.util.Timer;
import java.util.TimerTask;
import android.content.Context;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
public class MyLocation
Timer timer1;
LocationManager lm;
LocationResult locationResult;
boolean gps_enabled=false;
boolean network_enabled=false;
public boolean getLocation(Context context, LocationResult result)
//I use LocationResult callback class to pass location value from MyLocation to user code.
locationResult=result;
if(lm==null)
lm = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
//exceptions will be thrown if provider is not permitted.
trygps_enabled=lm.isProviderEnabled(LocationManager.GPS_PROVIDER);catch(Exception ex)
trynetwork_enabled=lm.isProviderEnabled(LocationManager.NETWORK_PROVIDER);catch(Exception ex)
//don't start listeners if no provider is enabled
if(!gps_enabled && !network_enabled)
return false;
if(gps_enabled)
lm.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, locationListenerGps);
if(network_enabled)
lm.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, locationListenerNetwork);
timer1=new Timer();
timer1.schedule(new GetLastLocation(), 20000);
return true;
LocationListener locationListenerGps = new LocationListener()
public void onLocationChanged(Location location)
timer1.cancel();
locationResult.gotLocation(location);
lm.removeUpdates(this);
lm.removeUpdates(locationListenerNetwork);
public void onProviderDisabled(String provider)
public void onProviderEnabled(String provider)
public void onStatusChanged(String provider, int status, Bundle extras)
;
LocationListener locationListenerNetwork = new LocationListener()
public void onLocationChanged(Location location)
timer1.cancel();
locationResult.gotLocation(location);
lm.removeUpdates(this);
lm.removeUpdates(locationListenerGps);
public void onProviderDisabled(String provider)
public void onProviderEnabled(String provider)
public void onStatusChanged(String provider, int status, Bundle extras)
;
class GetLastLocation extends TimerTask
@Override
public void run()
lm.removeUpdates(locationListenerGps);
lm.removeUpdates(locationListenerNetwork);
Location net_loc=null, gps_loc=null;
if(gps_enabled)
gps_loc=lm.getLastKnownLocation(LocationManager.GPS_PROVIDER);
if(network_enabled)
net_loc=lm.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
//if there are both values use the latest one
if(gps_loc!=null && net_loc!=null)
if(gps_loc.getTime()>net_loc.getTime())
locationResult.gotLocation(gps_loc);
else
locationResult.gotLocation(net_loc);
return;
if(gps_loc!=null)
locationResult.gotLocation(gps_loc);
return;
if(net_loc!=null)
locationResult.gotLocation(net_loc);
return;
locationResult.gotLocation(null);
public static abstract class LocationResult
public abstract void gotLocation(Location location);
可能有人也想修改我的逻辑。例如,如果您从网络提供商处获得更新,请不要停止侦听器,而是继续等待。 GPS 提供更准确的数据,因此值得等待。如果计时器到时并且您从网络而不是 GPS 获得更新,那么您可以使用从网络提供的值。
另一种方法是使用 LocationClient http://developer.android.com/training/location/retrieve-current.html。但它需要在用户设备上安装 Google Play Services apk。
【讨论】:
嗨 Fedor,谢谢你,它看起来与我最终为之前的项目所做的非常相似。这或多或少是引发这个问题的原因:肯定有更简单的方法吗?! 作为记录,我的理解是google一般不建议使用android:configChanges。相反,我采用了一种解决方案,即注册 timertasks 并在 onDestroy 上取消它们。 这对我很有用!但是,我为我使用的活动会检查简历上的位置。如果用户在返回位置之前退出活动,则应用程序将崩溃。我通过将此方法添加到您的 MyLocation 类来解决此问题。public void cancelTimer() timer1.cancel(); lm.removeUpdates(locationListenerGps); lm.removeUpdates(locationListenerNetwork);我称之为 onPause() 并修复了崩溃。 如何通过这段代码获取位置?告诉我如何烤它或烤面包。 @Fedor,我确实有一个问题。我知道 GPS 在建筑物中不起作用,但如果我将其设置为仅在该位置上的 GPS 并尝试定位,则应用程序强制关闭。为了避免仅启用 GPS 而没有其他定位服务的情况下强制关闭,我需要做些什么特别的事情吗?【参考方案27】:使用 Fedor 的解决方案,我经历了多次执行回调 gotLocation
。
这似乎是由于被覆盖的LocationListener.onLocationChanged
方法中的竞态条件,而gotLocation 方法'足够长'。我不确定,但我猜removeUpdates
会阻止新消息在 Looper 队列中入队,但它不会删除那些已经入队但尚未使用的消息。因此是竞争条件。
为了减少这种错误行为的可能性,可以在触发 onLocationChanged 事件之前调用 removeUpdates,但我们仍然有竞争条件。
我发现的最佳解决方案是将requestLocationUpdates
替换为requestSingleUpdate
。
这是我的版本,基于 Fedor 的解决方案,使用 Handler 向 looper 线程发送消息:
public class LocationResolver
private Timer timer;
private LocationManager locationManager;
private LocationResult locationResult;
private boolean gpsEnabled = false;
private boolean networkEnabled = false;
private Handler locationTimeoutHandler;
private final Callback locationTimeoutCallback = new Callback()
public boolean handleMessage(Message msg)
locationTimeoutFunc();
return true;
private void locationTimeoutFunc()
locationManager.removeUpdates(locationListenerGps);
locationManager.removeUpdates(locationListenerNetwork);
Location networkLocation = null, gpsLocation = null;
if (gpsEnabled)
gpsLocation = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
if (networkEnabled)
networkLocation = locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
// if there are both values use the latest one
if (gpsLocation != null && networkLocation != null)
if (gpsLocation.getTime() > networkLocation.getTime())
locationResult.gotLocation(gpsLocation);
else
locationResult.gotLocation(networkLocation);
return;
if (gpsLocation != null)
locationResult.gotLocation(gpsLocation);
return;
if (networkLocation != null)
locationResult.gotLocation(networkLocation);
return;
locationResult.gotLocation(null);
;
private final LocationListener locationListenerGps = new LocationListener()
public void onLocationChanged(Location location)
timer.cancel();
locationResult.gotLocation(location);
locationManager.removeUpdates(this);
locationManager.removeUpdates(locationListenerNetwork);
public void onProviderDisabled(String provider)
public void onProviderEnabled(String provider)
public void onStatusChanged(String provider, int status, Bundle extras)
;
private final LocationListener locationListenerNetwork = new LocationListener()
public void onLocationChanged(Location location)
timer.cancel();
locationResult.gotLocation(location);
locationManager.removeUpdates(this);
locationManager.removeUpdates(locationListenerGps);
public void onProviderDisabled(String provider)
public void onProviderEnabled(String provider)
public void onStatusChanged(String provider, int status, Bundle extras)
;
public void prepare()
locationTimeoutHandler = new Handler(locationTimeoutCallback);
public synchronized boolean getLocation(Context context, LocationResult result, int maxMillisToWait)
locationResult = result;
if (locationManager == null)
locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
// exceptions will be thrown if provider is not permitted.
try
gpsEnabled = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
catch (Exception ex)
try
networkEnabled = locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
catch (Exception ex)
// don't start listeners if no provider is enabled
if (!gpsEnabled && !networkEnabled)
return false;
if (gpsEnabled)
locationManager.requestSingleUpdate(LocationManager.GPS_PROVIDER, locationListenerGps, Looper.myLooper());
//locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, locationListenerGps);
if (networkEnabled)
locationManager.requestSingleUpdate(LocationManager.NETWORK_PROVIDER, locationListenerNetwork, Looper.myLooper());
//locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, locationListenerNetwork);
timer = new Timer();
timer.schedule(new GetLastLocationTask(), maxMillisToWait);
return true;
private class GetLastLocationTask extends TimerTask
@Override
public void run()
locationTimeoutHandler.sendEmptyMessage(0);
public static abstract class LocationResult
public abstract void gotLocation(Location location);
我从一个定制的弯针线程中使用这个类,如下所示:
public class LocationGetter
private final Context context;
private Location location = null;
private final Object gotLocationLock = new Object();
private final LocationResult locationResult = new LocationResult()
@Override
public void gotLocation(Location location)
synchronized (gotLocationLock)
LocationGetter.this.location = location;
gotLocationLock.notifyAll();
Looper.myLooper().quit();
;
public LocationGetter(Context context)
if (context == null)
throw new IllegalArgumentException("context == null");
this.context = context;
public synchronized Coordinates getLocation(int maxWaitingTime, int updateTimeout)
try
final int updateTimeoutPar = updateTimeout;
synchronized (gotLocationLock)
new Thread()
public void run()
Looper.prepare();
LocationResolver locationResolver = new LocationResolver();
locationResolver.prepare();
locationResolver.getLocation(context, locationResult, updateTimeoutPar);
Looper.loop();
.start();
gotLocationLock.wait(maxWaitingTime);
catch (InterruptedException e1)
e1.printStackTrace();
if (location != null)
coordinates = new Coordinates(location.getLatitude(), location.getLongitude());
else
coordinates = Coordinates.UNDEFINED;
return coordinates;
其中 Coordinates 是一个简单的类,具有两个属性:纬度和经度。
【讨论】:
有趣的是,无论如何,requestSingleUpdate 需要 API 级别 9。但是 +1 指出这一点。 @Eduardo:另一种可能性是使用与循环器关联的处理程序执行任务的代码,并通过向处理程序发送(空)消息来调用它。由于消息是在 looper 队列上序列化的,因此您可以手动删除(例如使用标志)竞争条件。这不需要 API Livel 9,但需要显式使用 looper。【参考方案28】:要获取并显示用户的当前位置,您还可以使用MyLocationOverlay
。假设您的活动中有一个mapView
字段。您需要做的就是显示用户位置:
myLocationOverlay = new MyLocationOverlay(this, mapView);
myLocationOverlay.enableMyLocation();
mapView.getOverlays().add(myLocationOverlay);
这会从 GPS 或网络获取当前位置。如果两者都失败,enableMyLocation()
将返回 false
。
至于该区域周围事物的位置,ItemizedOverlay
应该可以解决问题。
希望我没有误解你的问题。祝你好运。
【讨论】:
【参考方案29】:我不确定Location-Based Services 是否可以从 GPS 以外的其他基础设施获取位置,但根据那篇文章,这似乎是可能的:
应用程序可以调用任何 几种定位方式。
使用手机网络: 当前小区 ID 可用于 识别基站收发信台 (BTS) 设备正在通信 和那个 BTS 的位置。 显然,这种方法的准确性 取决于单元格的大小,并且 可能非常不准确。一个GSM小区 可能在 2 到 20 之间 直径公里。其他 与小区 ID 一起使用的技术可以 达到 150 米以内的精度。
使用卫星:全球 定位系统 (GPS),受控 美国国防部使用 由 24 颗卫星组成的星座 绕地球运行。 GPS 确定 通过计算设备的位置 时间信号的差异来自 不同的卫星到达 接收者。 GPS 信号经过编码,因此 移动设备必须配备 带 GPS 接收器。全球定位系统是 可能是最准确的方法 (如果 GPS 在 4 到 40 米之间 接收器可以清楚地看到天空), 但它有一些缺点: 硬件可能很昂贵,消耗 电池在使用中,并且需要 冷启动后进行一些热身 对可见卫星的初步修复。 它还遭受“峡谷效应” 在卫星能见度高的城市 是间歇性的。
使用短程 定位信标:在相对 小区域,例如单个 建设,局域网可以 提供位置以及其他 服务。例如,适当地 配备的设备可以使用蓝牙 短距离定位。
【讨论】:
@ElijahSaounkine 显然 npinti 没有听说过辅助 GPS。将来,您也许可以将他们监督的事情告知人们,而不是咄咄逼人。 @Sammy 5 年前我似乎比现在更紧张。就我的笔记而言,您所指的“未来”可能已经开始和结束了;)以上是关于在 Android 上获取用户当前位置的最简单、最可靠的方法是啥?的主要内容,如果未能解决你的问题,请参考以下文章
Android 怎么使用 最简单 的方法来获取手机当前的位置(获取手机当前的经,纬度),求详细
创建跨设备位置跟踪应用程序的最简单方法(全部 1 个应用程序)