项目开发的过程中,可能需要用到定位。例如大众点评,一进入就开始定位。有时,你需要得到当前的Longitude、Latitude,或者Address,或者只是City。这时,你可能会使用Google的GPS模块进行定位。这种例子在网上是大把的,不过在谈及百度定位之前,咱们先回顾一下Google定位的做法。
在Google的定位模块中,一般是GPS、Network或者基站方式。而且Google也提供了Criteria类给你定制你所需要的条件来进行定位,例如setAccuracy、setPowerRequirement、setAltitudeRequired等,然后由LocationManager 这个位置服务管理类getBestProvider获取当前最适合你的定位方式,然后getLastKnownLocation获得你要的Location。就这么简单!
但是,这种方式经常没有那么理想(或者是我本身了解还不够全面的问题),而百度API这种“神级”的定位方式也应运而生。为什么称它神级,如果你使用过就应该比较清楚:基本只需要Network即可定位,如果需要精确定位则需要开启GPS,而且速度极快。但它最大的缺点是模式化。什么是模式化,就是写那个代码的时候,有些人都不知道到底是为什么,而且它提供的Lib的类都是木有注释,需要的话就得上官网看。
不管怎样,下面给出一个例子代码:
/**
* This Activity is mainly responsible for the preparation of the Navigation data
* and Location information.
* @author XijieChen
*/
public class WelcomeActivity extends MapActivity {
/**
* Regist this Listener when execute OnCreate and remove it when execute OnDestroy.
*/
private LocationListener mLocationListener = null;
private MKSearch mMKSearch = null;
/**
* These four variables are the location data which will be used in
* all the application.
*/
private String CityAddress = null;
private String subLongitude = null;
private String subLatitude = null;
private String cityName = null;
LocationBean userLocation;
/**
* This variable will equal to 1 when the Location file is exist and it will equal to
* 0 on the contrary.
*/
private int Flag = 0;
private SharedPreferences settings = null;
/**
* This handler is mainly responsible for dealing with the message sent from threads.
*/
Handler newhandler = new Handler() {
public void handleMessage(Message msg) {
switch (msg.what) {
case Constant.WELCOME_DOWNLOADSUCCESS:
Intent intent = new Intent();
intent.setClass(WelcomeActivity.this, StartActivity.class);
startActivity(intent);
finish();//Finish the current activity.
break;
case Constant.WELCOME_STARTSEARCH:
try {
int Longitude = (int) (1000000 * Double.parseDouble(subLongitude));
int Latitude = (int) (1000000 * Double.parseDouble(subLatitude));
// Search the address in this GeoPoint.
mMKSearch.reverseGeocode(new GeoPoint(Latitude, Longitude));
} catch (Exception e) {
e.printStackTrace();
}
break;
case Constant.WELCOME_GETADDRESS:
GetCityFromAddress getCity = new GetCityFromAddress(CityAddress);
cityName = getCity.getCityFromAddress();
if(Flag == 0) {
userLocation.setLocationAddress(CityAddress);
userLocation.setCity(cityName);
WriteLocation write = new WriteLocation(userLocation,settings);
write.WriteLocationData();
}
// Start the download thread to download the navigation data.
DownLoadThread downLoadThread = new DownLoadThread(userLocation.getCity());
downLoadThread.start();
break;
}
super.handleMessage(msg);
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.requestWindowFeature(Window.FEATURE_NO_TITLE);
this.requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
setContentView(R.layout.activity_welcome);
settings = getPreferences(Activity.MODE_APPEND);
initLocationData(settings);
}
/**
* Initialize the Location data and judge whether the location SharedPreferences
* is exist or not at the same time.
*/
private void initLocationData(SharedPreferences settings) {
ReadLocation read = new ReadLocation(settings);
if(read.GetLocation() != null) {
userLocation = read.GetLocation();
Flag = 1;//It means that the location SharedPreferences is exist.
newhandler.obtainMessage(Constant.WELCOME_DOWNLOADSUCCESS).sendToTarget();
} else {
userLocation = new LocationBean();
Flag = 0;//It means that the location SharedPreferences isn't exist.
ApplicationData app = (ApplicationData) this.getApplication();
if (app.mBMapMan == null) {
app.mBMapMan = new BMapManager(getApplication());
app.mBMapMan.init(app.mStrKey, new ApplicationData.MyGeneralListener());
}
app.mBMapMan.start();
WRSearchListener wrtempListener = new WRSearchListener();
mMKSearch = new MKSearch();
mMKSearch.init(app.mBMapMan, wrtempListener);// To initialize the MKSearch
mLocationListener = new LocationListener() {
public void onLocationChanged(Location location) {
if (location != null) {
StringBuilder longitude = new StringBuilder("" + location.getLongitude());
subLongitude = (String) longitude.subSequence(0, 10);
StringBuilder latitude = new StringBuilder("" + location.getLatitude());
subLatitude = (String) latitude.subSequence(0, 9);
userLocation.setLongitude(subLongitude);
userLocation.setLatitude(subLatitude);
newhandler.obtainMessage(Constant.WELCOME_STARTSEARCH).sendToTarget();
}
}
};
}
}
/**
* When the data download successfully, this thread is responsible for sending a
* DOWNLOADSUCCESS message to the newhandler.
*/
private class DownLoadThread extends Thread {
private String cityString = null;
public DownLoadThread(String city) {
cityString = city;
}
@Override
public void run() {
DownLoadNaviData navidata = new DownLoadNaviData(WelcomeActivity.this,cityString);
if (navidata.DownLoadData()) {
newhandler.obtainMessage(Constant.WELCOME_DOWNLOADSUCCESS).sendToTarget();
}
}
}
protected void onPause() {
if(Flag == 0) {
ApplicationData app = (ApplicationData) this.getApplication();
app.mBMapMan.getLocationManager().removeUpdates(mLocationListener);
app.mBMapMan.stop();
}
ApplicationData.userLocation = userLocation;
super.onPause();
}
protected void onResume() {
if(Flag == 0) {
ApplicationData app = (ApplicationData) this.getApplication();
app.mBMapMan.getLocationManager().requestLocationUpdates(mLocationListener);
app.mBMapMan.start();
}
super.onResume();
}
protected void onDestroy() {
ApplicationData app = (ApplicationData) this.getApplication();
if (app.mBMapMan != null) {
app.mBMapMan.destroy();
app.mBMapMan = null;
}
super.onDestroy();
}
@Override
public void onBackPressed() {
// TODO Auto-generated method stub
super.onBackPressed();
}
@Override
protected boolean isRouteDisplayed() {
// TODO Auto-generated method stub
return false;
}
/**
* Implement the MKSearchListener interface in order to search the address
* with the Logitude and the Latitude.
*/
public class WRSearchListener implements MKSearchListener {
public void onGetAddrResult(MKAddrInfo result, int iError) {
if (result == null) {
return;
}
StringBuffer sb = new StringBuffer();
sb.append(result.strAddr);// The location depends on its Logitude and Latitude.
CityAddress = sb.toString();
newhandler.obtainMessage(Constant.WELCOME_GETADDRESS).sendToTarget();
}
public void onGetDrivingRouteResult(MKDrivingRouteResult result, int iError) {
}
public void onGetPoiResult(MKPoiResult result, int type, int iError) {
}
public void onGetTransitRouteResult(MKTransitRouteResult result, int iError) {
}
public void onGetWalkingRouteResult(MKWalkingRouteResult result, int iError) {
}
}
}
在程序中,在Application的OnCreate中你会发现这样的代码:mBMapMan.init(this.mStrKey, new MyGeneralListener());其中 MyGeneralListener是继承了MKGeneralListener,Key就是从http://dev.baidu.com/wiki/static/imap/key/上申请得到的。实际上,上面那个代码就是在注册一个BMapManager类对象。
1、BMapManager:注册该类,用于得到LocationManager,获取位置信息;
2、LocationListener:BMapManager要start前,需要requestLocationUpdates添加一个LocationListener。主要从该事件中onLocationChanged获取Location,从而获取Longitude、Latitude;(一般经纬度的获取是秒级的)
3、MKSearch:需要BMapManager的对象,以及一个实现了MKSearchListener的事件对象,进行init;
4、GeoPoint:使用你前面获得的Longitude、Latitude去new一个GeoPoint。值得注意的是,GeoPoint使用的经纬度必须是int型,所以首先必须将你的Longitude、Latitude转换为int。原因很简单,int运算速度快;
5、使用MKSearch的对象对一个GeoPoint进行reverseGeocode,这个时候,在你实现了MKSearchListener的事件对象中onGetAddrResult即可得到MKAddrInfo result,其中result就是你要的Address了。(一般情况下可以定位到市区,GPS下可以准确到街道门牌号,神级!!)
另外,百度这种定位强大在就算你使用它定位成功,其实你也不清楚里面的原理的,因为百度压根就没有告诉你,你会发现IDE中的类都是没有JavaDoc的。。。(或许是我学艺不精,还不理解吧,如果是这样,还望各位不吝指教)