什么是在Android上获取用户当前位置的最简单,最健壮的方法?
Android上的LocationManager
API似乎对于只需要偶尔和粗略地近似用户位置的应用程序来说是一种痛苦。
我正在开发的应用程序本身并不是一个位置应用程序,但它确实需要获取用户的位置才能显示附近的商家列表。 不需要担心用户是否正在移动或类似的东西。
这是我想要做的:
- 向用户显示附近位置的列表。
- 预先载入用户的位置,以便在
Activity
X中需要它时,它将可用。 - 我不特别关心更新的准确性或频率。 只要抓住一个位置就足够了。 也许如果我想要看到我会每隔几分钟更新一次位置,但这不是一个重要的优先事项。
- 适用于任何设备,只要它有GPS或networking位置提供商。
似乎不应该那么难,但在我看来,我必须启动两个不同的位置提供商(GPS和NETWORK)并pipe理每个生命周期。 不仅如此,我还必须在多个活动中复制相同的代码来满足#2。 过去我尝试过使用getBestProvider()
来将解决scheme简化为只使用一个位置提供者,但是这似乎只给你最好的“理论”提供者,而不是实际上会给你提供最好结果的提供者。
有一个更简单的方法来完成这个吗?
这就是我所做的:
- 首先我检查提供者是否启用。 有些可能在设备上被禁用,有些可能在应用程序清单中被禁用。
- 如果有任何提供者可用,我启动位置侦听器和超时定时器。 在我的例子中是20秒,对于GPS来说可能不够,所以你可以放大它。
- 如果我从位置侦听器获取更新,则使用提供的值。 我停止听众和计时器。
- 如果我没有得到任何更新和计时器,我必须使用最后已知的值。
- 我从可用的提供者中获取最新的已知值,并select最近的值。
以下是我如何使用我的课程:
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); } }
有人可能也想修改我的逻辑。 例如,如果您从networking提供商获得更新不停止监听,但继续等待。 GPS提供更准确的数据,所以值得等待。 如果计时器过去了,你已经从networking更新,但没有从GPS更新,那么你可以使用从networking提供的价值。
还有一种方法是使用LocationClient http://developer.android.com/training/location/retrieve-current.html 。 但是它需要将Google Play服务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 finded 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
将尝试连接到min_gps_sat_count
卫星。 否则返回LocationManager.getBestProvider()
位置。 检查代码!
在Fedor的解决scheme中,我经历了gotLocation
多次执行。 这似乎是由于重写的LocationListener.onLocationChanged
方法中的竞争条件 ,当gotLocation方法是'足够长' 。 我不确定,但我想removeUpdates
可以阻止Looper队列中的新消息入队,但是它不会删除那些已经入队但还没有被使用的队列。 因此竞赛状况。
为了减less这种错误行为的可能性,可以在触发onLocationChanged事件之前调用removeUpdates,但是我们仍然有竞争条件。
我发现最好的解决scheme是用requestSingleUpdate
replacerequestLocationUpdates
。
这是我的版本,基于Fedor的解决scheme,使用处理程序发送消息给循环线程:
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; } }
坐标是一个简单的类,有两个属性:经度和纬度。
我已经创build了一步一步的小应用程序获取当前位置GPS坐标。
下面的URL中完整的示例源代码:
获取当前位置坐标,城市名称 – 在Android中
看看它怎么运作 :
-
我们所需要做的就是在manifest文件中添加这个权限
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"> </uses-permission>
-
并像这样创buildLocationManager实例
LocationManager locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
-
检查GPS是否启用
-
然后实现LocationListener和Get Coordinates
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(),但它像它说可能是过时的。
一个简单的方法来获得一个普通的位置可以注册的networking(通常很快)。
LocationManager locationManager = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE); locationManager.requestLocationUpdates( LocationManager.NETWORK_PROVIDER, 1000, 1000, this);
然后再做
locationManager.removeUpdates(this);
在侦听器的onLocationChanged()
方法中。
我不确定基于位置的服务是否可以从除GPS以外的其他基础设施获取位置,但根据该文章,似乎是可能的:
应用程序可以调用几种types的定位方法中的任何一种。
使用移动电话networking:当前的小区ID可以用来识别设备正在与之通信的基站收发信台(BTS)以及该BTS的位置。 显然,这种方法的准确性取决于单元的大小,并且可能相当不准确。 GSM小区的直径可能在2到20公里之间。 与小区ID一起使用的其他技术可以达到150米内的精度。
使用卫星:由美国国防部控制的全球定位系统(GPS)使用24颗围绕地球轨道运行的卫星。 GPS通过计算来自不同卫星到达接收机的时间信号的差值来确定设备的位置。 GPS信号被编码,所以移动设备必须配备GPS接收机。 GPS可能是最准确的方法(如果GPS接收机有清晰的天空观测,则在4到40米之间),但是它有一些缺点:额外的硬件可能是昂贵的,在使用时会消耗电池,在冷启动后才能对可见卫星进行初步修复。 在卫星能见度不连续的城市,它也受到“峡谷效应”的影响。
使用短距离定位信标:在相对较小的区域中,如单个build筑物,局域网可以提供位置以及其他服务。 例如,适当配备的设备可以使用蓝牙进行短程定位。
使用下面的代码,它会给最好的提供者:
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; } } }
实际上我们可以使用这两个提供者。 他们只是分享一个公众的听众:
locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 10 * 1000, (float) 10.0, listener); locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 90 * 1000, (float) 10.0, listener);
这是必要的,因为OnLocationChanged()方法总是需要及时调用。
我已经在demonuts.com上撰写了关于当前位置的详细教程。您可以在这里find更多描述,也可以下载整个演示源代码以便更好地理解。
在那里已经有很多答案了,但是我想用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) { }
Don't forget to start GPS in your device before running app.
This is the code that provides user current location
create Maps Activty:
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_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>
and define following permission in manifest:
<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"/>
To get and show the user's current location, you could also use MyLocationOverlay
. Suppose you have a mapView
field in your activity. All you would need to do to show the user location is the following:
myLocationOverlay = new MyLocationOverlay(this, mapView); myLocationOverlay.enableMyLocation(); mapView.getOverlays().add(myLocationOverlay);
This gets the current location from either the GPS or the network. If both fail, enableMyLocation()
will return false
.
As for the locations of things around the area, an ItemizedOverlay
should do the trick.
I hope I haven't misunderstood your question. 祝你好运。
EDIT: Updated with the latest Location Service API from Google Play Services library (July 2014)
I would recommend you to use the new Location Service API , available from the Google Play Services library, which provides a more powerful, high-level framework that automates tasks such as location provider choice and power management. According to the official documentation: "… Location API make it easy for you to build location-aware applications, without needing to focus on the details of the underlying location technology. They also let you minimize power consumption by using all of the capabilities of the device hardware."
For further information visit: Making Your App Location-Aware
To see a full example using the latest Location Service API visit: Android LocationClient class is deprecated but used in documentation
Even though the answer is already given here. I just wanted to share this to the world incase the come across such scenario.
My requirement was that i needed to get a user's current location within 30 to 35 seconds at max so here is the solution i made following Nirav Ranpara's Answer .
1. I made MyLocationManager.java class which handles all the GPS and Network stuff
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. I made an Interface (callback) OnLocationDetectectionListener.java in order to communicate the results back to the calling fragment or activity
import android.location.Location; public interface OnLocationDetectectionListener { public void onLocationDetected(Location mLocation); }
3. Then i made an MainAppActivty.java Activity that implements OnLocationDetectectionListener
interface and here is how i receive my location in it
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. Add the following permissions to your manifest file
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
Hope this is helpful to others 🙂
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; }
Simple and best way for 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(); }
A bit late here but what I would in such a situation is to use Google Maps API and mark the nearby locations using lat and long API of google maps. Plus user experience is better if you can show his/her location on a map. No need to bother about the updation of user location or frisking with android api. Let google maps handle the internals for you.
@emmby may have got it resolved in his app but for future reference a look at Google maps API for location specific stuff is what I recommend to fellow developers.
Edit: Link for displaying user location in google maps
It requires lots of things in place to get location updates in android, requires lots of bolierplate code.
You need to take care of
- Google Play services availablity Check,
- Update Google play Service if it is old or not available
- Dialog Creation of GoogleApiClient and its callbacks connected,disconnected etc.
- Stopping and releasing resources for location updates
- Handling Location permission scenarios
- Checking Location services are On or Off
- Getting lastknown location is not so easy either
- Fallback to last known location if not getting location after certain duration
I have created Android-EasyLocation (small android library) which will take care all this stuff and you can focus on business logic.
All you need is extend EasyLocationActivity and this
requestSingleLocationFix(easyLocationRequest);
要么
requestLocationUpdates(easyLocationRequest);
Checkout sample app and steps needed here at https://github.com/akhgupta/Android-EasyLocation
By using FusedLocationProviderApi which is the latest API and the best among the available possibilities to get location in Android. add this in build.gradle file
dependencies { compile 'com.google.android.gms:play-services:6.5.87' }
you can get full source code by this url http://javapapers.com/android/android-location-fused-provider/
这就是我所做的:
- First of all I check whether NETWORK or GPS providers are enabled. Some may be disabled on the device, some may be disabled in application manifest. If any provider is enabled, I fetch cached last location for this provider and start location update listeners for this provider.
- There is a method to determine whether a location is better than last received location as mentioned in link :- https://developer.android.com/guide/topics/location/strategies.html#BestEstimate
- If I get update from location listener I check whether this location is better than previously received location. and If it is better than replace this location to previous best location(
mFinalLocation
). - There is also a handler(timer) for two minutes, which eventually stops the service and in
onDestroy()
method of service, stop listening for location updates for each of the provider.
Below is the code for service. You can run it based upon frequency of location update you need.
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); } } } } }
Before I answer, I just want to be upfront about the fact that I'm affiliated with Neura. Now to your question. So, instead of wasting your time behind coding to get your user's location, you can use our SDK. It takes less than 30 mins to integrate. Neura provides you with your user's location/activity,and you can configure your application accordingly to perform certain tasks after you receive the data. Here's a few reasons to use Neura over other Activity recognition API's:
- No need to code tons of lines to understand your user.
- Gives you accurate results.
- Consumes less than 1% of your battery.