基于基站和GPS的LBS定位

时间:2022-12-13 14:29:12

1. 写一个获取GPS信息的处理类,这个类用到的知识基本就是LocationManager的CallBack和系统提供的NetworkProvider 和GPSProvider, 代码如下:

public class MyLocationListener implements LocationListener {
    private static final String TAG = "BestLocationListener";
    private static final boolean DEBUG = true;

    public static final long LOCATION_UPDATE_MIN_TIME = 0;
    public static final long LOCATION_UPDATE_MIN_DISTANCE = 0;

    public static final long SLOW_LOCATION_UPDATE_MIN_TIME = 1000 * 60 * 5;
    public static final long SLOW_LOCATION_UPDATE_MIN_DISTANCE = 50;

    public static final float REQUESTED_FIRST_SEARCH_ACCURACY_IN_METERS = 100.0f;
    public static final int REQUESTED_FIRST_SEARCH_MAX_DELTA_THRESHOLD = 1000 * 60 * 5;

    public static final long LOCATION_UPDATE_MAX_DELTA_THRESHOLD = 1000 * 60 * 5;

    private Location mLastLocation;
    private LocationObservable mObservable;

    public MyLocationListener(LocationObservable observable) {
        super();
        mObservable = observable;
    }

    @Override
    public void onLocationChanged(Location location) {
        if (DEBUG) Log.d(TAG, "onLocationChanged: " + location);
        updateLocation(location);
    }

    @Override
    public void onProviderDisabled(String provider) {
        // do nothing.
    }

    @Override
    public void onProviderEnabled(String provider) {
        // do nothing.
    }

    @Override
    public void onStatusChanged(String provider, int status, Bundle extras) {
        // do nothing.
    }

    synchronized public void onBestLocationChanged(Location location) {
        if (DEBUG) Log.d(TAG, "onBestLocationChanged: " + location);
        mLastLocation = location;
        //setChanged();
        //notifyObservers(location);
        if (mObservable != null){
        	mObservable.updateLocation(location);
        }
    }

    synchronized public Location getLastKnownLocation() {
        return mLastLocation;
    }

    public void updateLocation(Location location) {
        if (DEBUG) {
            Log.d(TAG, "updateLocation: Old: " + mLastLocation);
            Log.d(TAG, "updateLocation: New: " + location);
        }

        // Cases where we only have one or the other.
        if (location != null && mLastLocation == null) {
            if (DEBUG) Log.d(TAG, "updateLocation: Null last location");
            onBestLocationChanged(location);
            return;

        } else if (location == null) {
            if (DEBUG) Log.d(TAG, "updated location is null, doing nothing");
            return;
        }

        long now = new Date().getTime();
        long locationUpdateDelta = now - location.getTime();
        long lastLocationUpdateDelta = now - mLastLocation.getTime();
        boolean locationIsInTimeThreshold = locationUpdateDelta <= LOCATION_UPDATE_MAX_DELTA_THRESHOLD;
        boolean lastLocationIsInTimeThreshold = lastLocationUpdateDelta <= LOCATION_UPDATE_MAX_DELTA_THRESHOLD;
        boolean locationIsMostRecent = locationUpdateDelta <= lastLocationUpdateDelta;

        boolean accuracyComparable = location.hasAccuracy() || mLastLocation.hasAccuracy();
        boolean locationIsMostAccurate = false;
        if (accuracyComparable) {
            // If we have only one side of the accuracy, that one is more
            // accurate.
            if (location.hasAccuracy() && !mLastLocation.hasAccuracy()) {
                locationIsMostAccurate = true;
            } else if (!location.hasAccuracy() && mLastLocation.hasAccuracy()) {
                locationIsMostAccurate = false;
            } else {
                // If we have both accuracies, do a real comparison.
                locationIsMostAccurate = location.getAccuracy() <= mLastLocation.getAccuracy();
            }
        }

        if (DEBUG) {
            Log.d(TAG, "locationIsMostRecent:\t\t\t" + locationIsMostRecent);
            Log.d(TAG, "locationUpdateDelta:\t\t\t" + locationUpdateDelta);
            Log.d(TAG, "lastLocationUpdateDelta:\t\t" + lastLocationUpdateDelta);
            Log.d(TAG, "locationIsInTimeThreshold:\t\t" + locationIsInTimeThreshold);
            Log.d(TAG, "lastLocationIsInTimeThreshold:\t" + lastLocationIsInTimeThreshold);

            Log.d(TAG, "accuracyComparable:\t\t\t" + accuracyComparable);
            Log.d(TAG, "locationIsMostAccurate:\t\t" + locationIsMostAccurate);
        }

        // Update location if its more accurate and w/in time threshold or if
        // the old location is
        // too old and this update is newer.
        if (accuracyComparable && locationIsMostAccurate && locationIsInTimeThreshold) {
            onBestLocationChanged(location);
        } else if (locationIsInTimeThreshold && !lastLocationIsInTimeThreshold) {
            onBestLocationChanged(location);
        }
    }

    public boolean isAccurateEnough(Location location) {
        if (location != null && location.hasAccuracy()
                && location.getAccuracy() <= REQUESTED_FIRST_SEARCH_ACCURACY_IN_METERS) {
            long locationUpdateDelta = new Date().getTime() - location.getTime();
            if (locationUpdateDelta < REQUESTED_FIRST_SEARCH_MAX_DELTA_THRESHOLD) {
                if (DEBUG) Log.d(TAG, "Location is accurate: " + location.toString());
                return true;
            }
        }
        if (DEBUG) Log.d(TAG, "Location is not accurate: " + String.valueOf(location));
        return false;
    }

    public void register(LocationManager locationManager, boolean gps) {
        if (DEBUG) Log.d(TAG, "Registering this location listener: " + this.toString());
        long updateMinTime = SLOW_LOCATION_UPDATE_MIN_TIME;
        long updateMinDistance = SLOW_LOCATION_UPDATE_MIN_DISTANCE;
        if (gps) {
            updateMinTime = LOCATION_UPDATE_MIN_TIME;
            updateMinDistance = LOCATION_UPDATE_MIN_DISTANCE;
        }
        List<String> providers = locationManager.getProviders(true);
        int providersCount = providers.size();
        for (int i = 0; i < providersCount; i++) {
            String providerName = providers.get(i);
            if (locationManager.isProviderEnabled(providerName)) {
                updateLocation(locationManager.getLastKnownLocation(providerName));
            }
            // Only register with GPS if we've explicitly allowed it.
            if (gps || !LocationManager.GPS_PROVIDER.equals(providerName)) {
                locationManager.requestLocationUpdates(providerName, updateMinTime,
                        updateMinDistance, this);
            }
        }
    }

    public void unregister(LocationManager locationManager) {
        if (DEBUG) Log.d(TAG, "Unregistering this location listener: " + this.toString());
        locationManager.removeUpdates(this);
    }

    /**
     * Updates the current location with the last known location without
     * registering any location listeners.
     * 
     * @param locationManager the LocationManager instance from which to
     *            retrieve the latest known location
     */
    synchronized public void updateLastKnownLocation(LocationManager locationManager) {
        List<String> providers = locationManager.getProviders(true);
        for (int i = 0, providersCount = providers.size(); i < providersCount; i++) {
            String providerName = providers.get(i);
            if (locationManager.isProviderEnabled(providerName)) {
                updateLocation(locationManager.getLastKnownLocation(providerName));
            }
        }
    }
    
	private Criteria getCriteria(){
		Criteria cr = new Criteria();
		
		// query precision
		cr.setAccuracy(Criteria.ACCURACY_FINE);
		
		// whether query altitude
		cr.setAltitudeRequired(false);
		
		// whether query direction
		cr.setBearingRequired(false);
		
		// whether desire cost
		cr.setCostAllowed(true);
			
		// power requirement is low
		cr.setPowerRequirement(Criteria.POWER_LOW);
		
		return cr;
	}
}

2. UI类用于反编译Location地址成物理地址(我这儿使用的反编用的是高德的库,如果是用SDK默认的接口,也就是我注释起来的部分来反编译出来的定位只能定位到区,而用Google API来编译就需要上传基站地址到Google,然后Google会返回一个JSON文件,Google返回的数据可以定位到街道,它就没有POI部分的数据,这种上传基站定们的方式又叫AGPS, 除这三种方法还可以用百度的GPS API效果和高德差不多)

http://ouyangfeng521.iteye.com/blog/1064382

http://topic.csdn.net/u/20110110/23/C2F6524A-8746-4C1B-914E-57C7C9CCED02.html

public class GPSLib extends Activity implements LocationObservable{
	private LocationManager	mLocationManager;
	private MyLocationListener mLocationListener;

	// view
	private TextView mShowInfo;
	private Handler mHandler = new Handler(){
		public void handleMessage(android.os.Message msg) {
			if (msg.what == 1){
				mShowInfo.setText((String)msg.obj);
			}
		};
	};

	/** Called when the activity is first created. */
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);

		mLocationManager = (LocationManager)getSystemService(Context.LOCATION_SERVICE);
		mLocationListener = new MyLocationListener(this);

		((Button)findViewById(R.id.get_location)).setOnClickListener(
				new OnClickListener(){
					@Override
					public void onClick(View v) {
						mLocationListener.register(mLocationManager, true);
					}
				});

		mShowInfo = (TextView)findViewById(R.id.show_gps_info);
	}

	@Override
	protected void onDestroy() {
		// TODO Auto-generated method stub
		mLocationListener.unregister(mLocationManager);
		super.onDestroy();
	}
	
	@Override
	public void updateLocation(final Location location) {
		if (location != null){
			mHandler.post(new Runnable() {
				@Override
				public void run() {
					callGaoWithGeo(location, getApplicationContext());
				}
			});
			
			//String address = getStreetAddress(location);
			//if (address != null){
			//	mShowInfo.setText(address);
			//}
		}
	}

	//Android sdk 返编辑
//	private String getStreetAddress(Location location){
//		String addressString=null;
//
//		if (location != null){
//			double latitude = location.getLatitude();
//			double longitude = location.getLongitude();
//
//			Geocoder gc = new Geocoder(this, Locale.getDefault());
//
//			try{
//				List<Address> addresses = gc.getFromLocation(latitude, longitude, 8);
//				StringBuilder sb = new StringBuilder();
//
//				for(int j=0; j <addresses.size(); j++){
//					Address address = addresses.get(j);
//					sb.append(address.getCountryName());
//					sb.append(address.getLocality());
//					for (int i = 0; i < address.getMaxAddressLineIndex(); i++)
//						sb.append(address.getAddressLine(i));
//					sb.append("\n");
//				}
//
//				addressString = sb.toString();
//			}
//			catch (IOException e) {
//				// TODO: handle exception
//				e.printStackTrace();
//			}
//		}
//
//		return addressString;
//	}

	//高德反编码方式
	synchronized public Location callGaoWithGeo(Location location,Context context) {
		double mLat = location.getLatitude();
		double mLon = location.getLongitude();
		// 用给定的经纬度构造一个GeoPoint,单位是微度 (度 * 1E6)
		GeoPoint geo = new GeoPoint((int) (mLat * 1E6),
				(int) (mLon * 1E6));
		try {
			if (geo.toString() != "") {
				Geocoder mGeocoder01 = new Geocoder(context, Locale.getDefault().toString());
				int x = geo.getLatitudeE6(); // 得到geo纬度,单位微度 (度 * 1E6)
				double x1 = ((double) x) / 1000000;
				int y = geo.getLongitudeE6(); // 得到geo经度,单位微度 (度 * 1E6)
				double y1 = ((double) y) / 1000000;
				//得到逆理编码,参数分别为:纬度,经度,最大结果集

				List<Address> lstAddress = mGeocoder01.getFromRawGpsLocation(x1, y1, 3);
				if (lstAddress.size()!=0) {
					Location loc = new Location(location);

					Address adsLocation = null;
					for (int i = 0; i < lstAddress.size(); ++i) {
						adsLocation = lstAddress.get(i);
						String pr = adsLocation.getPremises();
						//Log.i("joseph", "Address found = "+ adsLocation.toString());

						if(pr.equals(Geocoder.POI)){
							loc.setLongitude(adsLocation.getLongitude());
							loc.setLatitude(adsLocation.getLatitude());
							break;
						}
					}

					if (adsLocation != null){
						mShowInfo.setText(adsLocation.getAddressLine(0) + " "
								+ adsLocation.getLocality() + " "
								+ adsLocation.getAdminArea()+" "
								+ adsLocation.getCountryName() + "\n"
								+ adsLocation.getLatitude() + "," + adsLocation.getLongitude());
					}
					else{
						mShowInfo.setText("获取数据失败!");
					}

					return loc;
				} else {
					Log.i("joseph", "Address GeoPoint NOT Found.");
				}
			}
		} catch (Exception e) {
			e.printStackTrace();

		}

		return location;
	}
}

3. 一个CallBack的接口类,到LocationManager类获取到Location数据时, 通知给UI类

public interface LocationObservable {
	public void updateLocation(Location location);
}


4. 添加permission

<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"></uses-permission>
<uses-permission android:name="android.permission.ACCESS_MOCK_LOCATION"></uses-permission>
<uses-permission android:name="android.permission.UPDATE_DEVICE_STATS"></uses-permission>