|
最近为了做LBS功能模块,到网上搜了一些资料,大多数介绍都是使用繁琐的基站定位,要自己去读取什么CellId,LocationAreaCode, MobileCountryCode,MobileNetworkCode等参数,而且多数是针对GSM/UMTS。而自己使用的CDMA,跟上面的参数叫法不一样,还得自己一个一个去对应。虽然最后算是解决了,但是难道就没有更好的办法吗。
翻了翻Android Developer找到一个不错的东西LocationManager。LocationManager是通过listener的方式来告知调用者,而原来写好的模块是直接return的,于是得稍微改造一下:
首先定义一个Model:- public class LocationData {
- String lat;
- String lon;
- String address;
- }
|
然后LBS的所有功能都封装到一个工具类里面:
首先在构造函数里面获取系统服务中的LocationManager:
- public class LBSTool {
- private Context mContext;
- private LocationManager mLocationManager;
- private LocationData mLocation;
- private LBSThread mLBSThread;
- private MyLocationListner mNetworkListner;
- private MyLocationListner mGPSListener;
- private Looper mLooper;
- public LBSTool(Context context) {
- mContext = context;
- //获取Location manager
- mLocationManager = (LocationManager)mContext.getSystemService(Context.LOCATION_SERVICE);
- }
- ......
- }
|
然后是入口方法,这里会启动一个子线程去获取地理位置信息,并让主线程进入等待,时长通过timeout设置
- /**
- * 开始定位
- * @param timeout 超时设置
- * @return LocationData位置数据,如果超时则为null
- */
- public LocationData getLocation( long timeout) {
- mLocation = null ;
- mLBSThread = new LBSThread();
- mLBSThread.start(); //启动LBSThread
- timeout = timeout > 0 ? timeout : 0 ;
- synchronized (mLBSThread) {
- try {
- Log.i(Thread.currentThread().getName(), "Waiting for LocationThread to complete..." );
- mLBSThread.wait(timeout); //主线程进入等待,等待时长timeout ms
- Log.i(Thread.currentThread().getName(), "Completed.Now back to main thread" );
- }
- catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- mLBSThread = null ;
- return mLocation;
- }
|
子线程通过调用registerLocationListener开启位置服务的监听,并且讲监听器分配给指定looper
- private class LBSThread extends Thread {
- @Override
- public void run() {
- setName( "location thread" );
- Log.i(Thread.currentThread().getName(), "--start--" );
- Looper.prepare(); //给LBSThread加上Looper
- mLooper = Looper.myLooper();
- registerLocationListener();
- Looper.loop();
- Log.e(Thread.currentThread().getName(), "--end--" );
- }
- }
- private void registerLocationListener () {
- Log.i(Thread.currentThread().getName(), "registerLocationListener" );
- if (isGPSEnabled()) {
- mGPSListener= new MyLocationListner();
- //五个参数分别为位置服务的提供者,最短通知时间间隔,最小位置变化,listener,listener所在消息队列的looper
- mLocationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 5000 , 0 , mGPSListener, mLooper);
- }
- if (isNetworkEnabled()) {
- mNetworkListner= new MyLocationListner();
- mLocationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 3000 , 0 , mNetworkListner, mLooper);
- }
- }
|
isGPSEnabled和isNetworkEnabled分别为判断当前手机是否开启了GPS以及网络的状况(包含了是否开启wifi和移动网络),以决定使用哪一种服务提供者:GPS_PROVIDER或者NETWORK_PROVIDER。
- /**
- * 判断GPS是否开启
- * @return
- */
- public boolean isGPSEnabled() {
- if (mLocationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)) {
- Log.i(Thread.currentThread().getName(), "isGPSEnabled" );
- return true ;
- }
- else {
- return false ;
- }
- }
- /**
- * 判断Network是否开启(包括移动网络和wifi)
- * @return
- */
- public boolean isNetworkEnabled() {
- return (isWIFIEnabled() || isTelephonyEnabled());
- }
- /**
- * 判断移动网络是否开启
- * @return
- */
- public boolean isTelephonyEnabled() {
- boolean enable = false ;
- TelephonyManager telephonyManager = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
- if (telephonyManager != null ) {
- if (telephonyManager.getNetworkType() != TelephonyManager.NETWORK_TYPE_UNKNOWN) {
- enable = true ;
- Log.i(Thread.currentThread().getName(), "isTelephonyEnabled" );
- }
- }
- return enable;
- }
- /**
- * 判断wifi是否开启
- */
- public boolean isWIFIEnabled() {
- boolean enable = false ;
- WifiManager wifiManager = (WifiManager)mContext.getSystemService(Context.WIFI_SERVICE);
- if (wifiManager.isWifiEnabled()) {
- enable = true ;
- Log.i(Thread.currentThread().getName(), "isWIFIEnabled" );
- }
- return enable;
- }
|
当LocationManager在大于最短时间且检测到最小位置变化时,就会通知给监听器,然后我们就可以通过返回的经纬度信息去google服务器查找对应的地址,然后停止LocationManger的工作,解除LBSThread中的Looper,让LBSThread结束,最后通知主线程可以继续,整个流程结束。
- private class MyLocationListner implements LocationListener{
- @Override
- public void onLocationChanged(Location location) {
- // 当LocationManager检测到最小位置变化时,就会回调到这里
- Log.i(Thread.currentThread().getName(), "Got New Location of provider:" +location.getProvider());
- unRegisterLocationListener(); //停止LocationManager的工作
- try {
- synchronized (mLBSThread) {
- parseLatLon(location.getLatitude()+ "" , location.getLongitude()+ "" ); //解析地理位置
- mLooper.quit(); //解除LBSThread的Looper,LBSThread结束
- mLBSThread.notify(); //通知主线程继续
- }
- }
- catch (Exception e) {
- e.printStackTrace();
- }
- }
- //后3个方法此处不做处理
- @Override
- public void onStatusChanged(String provider, int status, Bundle extras) {}
- @Override
- public void onProviderEnabled(String provider) {}
- @Override
- public void onProviderDisabled(String provider) {}
- };
- /**
- * 使用经纬度从goole服务器获取对应地址
- * @param 经纬度
- */
- private void parseLatLon(String lat, String lon) throws Exception {
- Log.e(Thread.currentThread().getName(), "---parseLatLon---" );
- Log.e(Thread.currentThread().getName(), "---" +lat+ "---" );
- try {
- HttpClient httpClient = new DefaultHttpClient();
- HttpGet get = new HttpGet( "http://ditu.google.cn/maps/geo?output=json&q=" +lat+ "," +lon);
- HttpResponse response = httpClient.execute(get);
- String resultString = EntityUtils.toString(response.getEntity());
- JSONObject jsonresult = new JSONObject(resultString);
- if (jsonresult.optJSONArray( "Placemark" ) != null ) {
- mLocation = new LocationData();
- mLocation.lat = lat;
- mLocation.lon = lon;
- mLocation.address = jsonresult.optJSONArray( "Placemark" ).optJSONObject( 0 ).optString( "address" );
- }
- }
- catch (Exception e) {
- e.printStackTrace();
- }
- }
- /**
- * 注销监听器
- */
- private void unRegisterLocationListener () {
- if (mGPSListener!= null ){
- mLocationManager.removeUpdates(mGPSListener);
- mGPSListener= null ;
- }
- if (mNetworkListner!= null ){
- mLocationManager.removeUpdates(mNetworkListner);
- mNetworkListner= null ;
- }
- }
|
接下来可以在界面上安放个button:
- locationBtn.setOnClickListener( new OnClickListener() {
- @Override
- public void onClick(View v) {
- //return mode
- LBSTool lbs = new LBSTool(LBStestActivity. this );
- LocationData location = lbs.getLocation( 120000 );
- if (location != null ) {
- Log.i( "---lat---" ,location.lat);
- Log.i( "---lon---" ,location.lon);
- Log.i( "---address---" ,location.address);
- Toast.makeText(LBStestActivity. this , location.lat + " " + location.lon + " " + location.address, Toast.LENGTH_LONG).show();
- }
- }
- });
|
最后别忘了加入权限:
- < uses-permission android:name = "android.permission.INTERNET" />
- < uses-permission android:name = "android.permission.ACCESS_NETWORK_STATE" />
- < uses-permission android:name = "android.permission.ACCESS_WIFI_STATE" />
- < uses-permission android:name = "android.permission.ACCESS_COARSE_LOCATION" />
- < uses-permission android:name = "android.permission.ACCESS_FINE_LOCATION" />
|
此外,LocationManager还有些高级的用法,比如设置一些关键参数,以及获取最后一次定位信息等等:
- Criteria criteria = new Criteria();
- criteria.setAccuracy(Criteria.ACCURACY_FINE); // 高精度
- criteria.setAltitudeRequired( false );
- criteria.setBearingRequired( false );
- criteria.setCostAllowed( true );
- criteria.setPowerRequirement(Criteria.POWER_LOW); // 低功耗
- String bestprovider = locationManager.getBestProvider(criteria, true ); // 获取GPS信息
- Location location = locationManager.getLastKnownLocation(bestprovider); // 通过GPS获取位置
- Log.e( "--bestprovider--" , bestprovider);
- Log.e( "--bestprovider--" , location.getLatitude()+ "" );
|
----------------------------
原文链接:https://blog.51cto.com/winwyf/875617
程序猿的技术大观园:www.javathinker.net
[这个贴子最后由 flybird 在 2020-04-17 12:34:41 重新编辑]
|
|