对于只需要偶尔粗略估计用户位置的应用程序,Android 上的 LocationManager
API 似乎有点痛苦。
我正在开发的应用程序本身并不是真正的位置应用程序,但它确实需要获取用户的位置才能显示附近企业的列表。它不需要担心用户是否在四处走动或类似的事情。
这是我想做的:
向用户显示附近位置的列表。预加载用户的位置,这样当我在 Activity X 中需要它时,它就可用了。我并不特别关心更新的准确性或频率。只要不远,只需抓住一个位置就足够了。也许如果我想变得花哨,我会每隔几分钟左右更新一次位置,但这不是一个重要的优先事项。只要有 GPS 或网络位置提供程序,它就可以适用于任何设备。
看起来它不应该那么难,但在我看来,我必须启动两个不同的位置提供程序(GPS 和 NETWORK)并管理每个位置的生命周期。不仅如此,我还必须在多个活动中复制相同的代码以满足#2。我过去曾尝试使用 getBestProvider()
将解决方案缩减为仅使用一个位置提供程序,但这似乎只能为您提供最佳的“理论”提供程序,而不是实际上会为您提供最佳结果的提供程序。
有没有更简单的方法来实现这一点?
这就是我所做的:
首先,我检查启用了哪些提供程序。有些可能在设备上被禁用,有些可能在应用程序清单中被禁用。如果有任何提供程序可用,我将启动位置侦听器和超时计时器。在我的例子中是 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.
try{gps_enabled=lm.isProviderEnabled(LocationManager.GPS_PROVIDER);}catch(Exception ex){}
try{network_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。
在搜索了如何获得最佳精确用户位置的最佳实现之后,我设法结合了所有最佳方法并提出了以下课程:
/**
* 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()
位置。检查代码!
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;
使用 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 是一个简单的类,具有两个属性:纬度和经度。
我创建了一个带有分步描述的小应用程序来获取当前位置的 GPS 坐标。
https://i.stack.imgur.com/m4DNb.jpg
以下 URL 中的完整示例源代码:
获取当前位置坐标,城市名称 - 在 Android
看看它怎么运作 :
我们需要做的就是在清单文件
并像这样创建 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) {}
}
您总是可以只使用 LocationManager.getLastKnownLocation() 但就像它说的那样它可能已经过时了。
获取大致位置的一种简单方法是注册网络(通常非常快)。
LocationManager locationManager = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE);
locationManager.requestLocationUpdates(
LocationManager.NETWORK_PROVIDER, 1000, 1000, this);
然后做
locationManager.removeUpdates(this);
在侦听器的 onLocationChanged()
方法中。
我在 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。
实际上,我们可以使用这两个提供商(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()
方法。
我不确定 Location-Based Services 是否可以从 GPS 以外的其他基础设施获取位置,但根据那篇文章,这似乎是可能的:
应用程序可以调用多种定位方法中的任何一种。使用移动电话网络:当前小区 ID 可用于识别设备正在与之通信的基站收发器 (BTS) 以及该 BTS 的位置。显然,这种方法的准确性取决于细胞的大小,并且可能非常不准确。一个 GSM 小区的直径可能在 2 到 20 公里之间。与小区 ID 一起使用的其他技术可以达到 150 米以内的精度。使用卫星:由美国国防部控制的全球定位系统 (GPS) 使用由 24 颗卫星组成的星座围绕地球运行。 GPS 通过计算来自不同卫星的信号到达接收器的时间差异来确定设备的位置。 GPS 信号经过编码,因此移动设备必须配备 GPS 接收器。 GPS 可能是最准确的方法(如果 GPS 接收器可以清楚地看到天空,则在 4 到 40 米之间),但它有一些缺点:额外的硬件可能很昂贵,使用时会消耗电池,并且需要一些温暖的温度。在冷启动后开始对可见卫星进行初步修复。在卫星能见度断断续续的城市,它还受到“峡谷效应”的影响。使用短距离定位信标:在相对较小的区域,例如单个建筑物,局域网可以提供位置以及其他服务。例如,适当配备的设备可以使用蓝牙进行短距离定位。
使用下面的代码,它将提供最好的提供者:
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);
推荐的方法是使用 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
连接时调用的方法。 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;
}
}
}
尽管这里已经给出了答案。我只是想与世界分享这一点,以防遇到这种情况。
我的要求是我需要在最多 30 到 35 秒内获得用户的当前位置,所以这是我在 Nirav Ranpara's Answer 之后提出的解决方案。
1. 我创建了处理所有 GPS 和网络内容的 MyLocationManager.java 类
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" />
希望这对其他人有帮助:)
@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 年弃用。
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;
}
这是我请求用户权限的方式。
在 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
在您的活动的 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
}
}
从过去一年多开始,我一直在使用 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" />
要获取并显示用户的当前位置,您还可以使用 MyLocationOverlay
。假设您的活动中有一个 mapView
字段。您需要做的就是显示用户位置:
myLocationOverlay = new MyLocationOverlay(this, mapView);
myLocationOverlay.enableMyLocation();
mapView.getOverlays().add(myLocationOverlay);
这可以从 GPS 或网络获取当前位置。如果两者都失败,enableMyLocation()
将返回 false
。
至于该区域周围事物的位置,ItemizedOverlay
应该可以解决问题。
我希望我没有误解你的问题。祝你好运。
这是提供用户当前位置的代码
创建地图活动:
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;
}
}
}
主.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/black"
android:orientation="vertical" >
<com.google.android.maps.MapView
android:id="@+id/map_container"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
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"/>
编辑:使用来自 Google Play 服务库的最新位置服务 API 进行了更新(2014 年 7 月)
我建议您使用 Google Play 服务库中提供的新 Location Service API,它提供了一个更强大的高级框架,可以自动执行位置提供程序选择和电源管理等任务。根据官方文档:“...... Location API 让您可以轻松构建位置感知应用程序,而无需关注底层定位技术的细节。它们还让您通过使用所有功能来最小化功耗设备硬件。”
如需更多信息,请访问:Making Your App Location-Aware
要查看使用最新位置服务 API 的完整示例,请访问:Android LocationClient class is deprecated but used in documentation
它需要很多东西才能在 android 中获取位置更新,需要大量的样板代码。
你需要照顾
Google Play 服务可用性检查,
更新旧的或不可用的 Google Play 服务
GoogleApiClient 的对话框创建及其回调连接、断开连接等。
停止和释放用于位置更新的资源
处理位置权限场景
检查位置服务是打开还是关闭
获取最后一个位置也不是那么容易
如果在一定时间后没有获得位置,则回退到最后一个已知位置
我创建了 Android-EasyLocation (small android library),它将处理所有这些事情,您可以专注于业务逻辑。
您所需要的只是扩展 EasyLocationActivity 和这个
requestSingleLocationFix(easyLocationRequest);
或者
requestLocationUpdates(easyLocationRequest);
在 https://github.com/akhgupta/Android-EasyLocation 处查看示例应用程序和所需的步骤
@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?)
}
}
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();
}
这里有点晚了,但在这种情况下我会使用谷歌地图 API 并使用谷歌地图的 lat 和 long API 标记附近的位置。另外,如果您可以在地图上显示他/她的位置,用户体验会更好。无需担心用户位置的更新或使用 android api 搜身。让谷歌地图为您处理内部问题。
@emmby 可能已经在他的应用程序中解决了这个问题,但为了将来的参考,我向其他开发人员推荐查看谷歌地图 API 以获取特定位置的东西。
编辑:显示 user location in google maps 的链接
这就是我所做的:
首先,我检查是否启用了 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);
}
}
}
}
}
在 Activity 类中制作了一个自定义方法:
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();
}
}
创建一个用户定义的类名 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();
}
}
其中一些ans现在已经过时了,所以我回答,
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
也没有帮助)。另见stackoverflow.com/questions/52587361/…、stackoverflow.com/questions/47521121/…。
我使用了这个 GPS 追踪器,它从 Android API 21 到 30 运行良好:
即使禁用网络并启用 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()
}
}
通过使用 FusedLocationProviderApi,它是最新的 API,也是在 Android 中获取位置的可用可能性中最好的。在 build.gradle 文件中添加这个
dependencies {
compile 'com.google.android.gms:play-services:6.5.87'
}
您可以通过此网址获取完整的源代码 http://javapapers.com/android/android-location-fused-provider/
最近重构获取代码的位置,学习了一些好的思路,终于实现了一个比较完善的库和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();
}
}
}
}
*每次请求完成定位,最好去掉Updates,否则手机状态栏会一直显示定位图标。
在看到所有答案和问题后(最简单和最强大)。我只点击了库 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 获取位置
自动完成建议