文章转载只能用于非商业性质,且不能带有虚拟货币、积分、注册等附加条件。转载须注明出处http://blog.csdn.net/flowingflying以及作者@恺风Wei。
LBS业务最常见的就是地图应用,Google提供Google Map,这属于Google Services APIs,而不是Android的APIs。而Google的服务对于中国区并不稳定,可以转用百度的LBS服务,具体可以参见http://lbsyun.baidu.com/sdk/download。无论采用哪一家的地图服务,都是使用其云资源,如何用,具体阅读提供者的指引。之前,我们就曾step by step地学习过Google Map v2的使用方法,具体可以参见Android学习笔记(五七):使用Google Map API v2。不清楚Google是否有升级到新的版本,反正现在访问不了相关的开发者网站(https://developers.google.com/maps/,正说着,网页转了几分钟,居然打开了,看到最后更新是2013.2.1,那么之前的文章应该还有效)。对于云服务的使用,一句话就是:照足指引。
我们将重点关于Android系统的android.location包所提供的能力,这个包有两个重要的类Geocoder和LocationManager。
Geocoder可以将一个地址转变为经纬度,或者将经纬度转变为地址。但是这个类左看右看都是需要和Map配合的,因为地址信息需要云端提供。
下面是代码片段
public void testGeocoder( ) {
double lat = 23.080006;
double lng = 113.174095;
//1:获取Geocoder对象
Geocoder geo = new Geocoder(this); //参数是context
try{
showInfo("start to test Geocoder!");
// 2:通过经纬度来获取地址,由于地址可能有多个,这和经纬度的精确度有关,本例限制最大返回数为5
List<Address> list = geo.getFromLocation(lat, lng, 5);
showInfo("list = " + list);
if(list != null){
for(int i = 0 ; i < list.size() ; i ++){
Address address = list.get(i);
showInfo("(" + i + ") location at " +address.getLongitude() + "," +address.getLatitude() +":" + address.getLocality());
}
}
}catch(Exception e){
Log.e("WEI","Error : " + e.toString());
}
}
private void showInfo(String info){
tv.setText(tv.getText() + info + "\n");
Log.i("WEI",info);
}
在不带有Google Services的模拟器中,马上返回空的list,需要带有Google Services的模拟器上测试,情况果然不同,下面是运行结果:
这说明Geocoder是需要通过Google Services来获得具体的结果,考虑到的Google服务确实也很不正常,决定使用了刷为百度云OS的实体机。我的估计是Geocoder是通过Map服务向云端请求答案,而提供Map的云服务会提供相应的Android SDK,对于百度云OS相信已经用其云服务替代Google Services,因此Geocoder很有可能有反应,实验结果如下:
从结果可以看到,给出的地理信息有很多,并不只是经纬度,Addess提供了getXXX()的方法来提前这些信息。在网络条件不理想的情况下,返回list=[]。
由于Google的服务不稳定,我们仍采用百度云OS来确保Geocoder有反馈,同样地采用百度的地图服务进行演示,最为简单地采用静态图片的方式,具体的接口可以参考:http://developer.baidu.com/map/index.php?title=static/static-1。代码片段如下:
public void doClick(View v){
WebView browser = (WebView)findViewById(R.id.web);
EditText ed = (EditText)findViewById(R.id.geo_location);
String place = ed.getText().toString();
try{
List<Address> list = geocoder.getFromLocationName(place, 5); //返回结果可能有多个,我们限制为5个,例如可能有N多的悦来客栈
if(list != null && list.size() > 0){
double lat = list.get(0).getLatitude();
double lng = list.get(0).getLongitude();
String url = "http://api.map.baidu.com/staticimage?center=" +
lng + "," + lat + "&width=" + browser.getWidth()
+ "&height=" +browser.getHeight() + "&zoom=14";
Log.i("WEI",url);
browser.loadUrl(url);
}else{
Log.d("WEI","list = " + list);
}
}catch(Exception e){
Toast.makeText(this, "Error : " + e.toString(), Toast.LENGTH_SHORT).show();
}
}
执行情况如下:
无论是经纬度查地址,还是地址查经纬度,在测试中,我们会发现有时结果返回有明显的时延,一方面和云服务的处理能力有关,而更多的和移动网络连接有关,当时延超过5秒时,就可以回触发ANR异常。因此合理的方式是在工作线程中处理GeoCoder。
我们仍用上面的小例子,用户在按button之后,弹出一个进度框,显示正在寻找该地方,同时开启一个工作线程,在线程中通过GeoCoder获取地点的经纬度,成功获取后,发送一个Handler Message,通知主线程(即UI线程)进行相应的处理。主线程收到Message后,关闭进度框,同时在WebView中显示相应的地图图片。新的小例子代码如下:
public class GeoTestBack extends Activity{
private WebView browser = null;
private EditText ed = null;
private Geocoder geocoder = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_geotest);
browser = (WebView)findViewById(R.id.web);
ed = (EditText)findViewById(R.id.geo_location);
geocoder = new Geocoder(this);
}
private ProgressDialog proDialog=null;
private List<Address> addressList = null;
public void doClick(View v){
String place = ed.getText().toString();
//(1)用户按button后,显示进度框
proDialog = ProgressDialog.show(this, "Processing ...", "Finding Location....",true,false);
//(2)启动查询地点经纬度的线程
findLocation(place);
}
//(2)启动查询地点经纬度的线程
private void findLocation(final String location){
Thread thread = new Thread(){
@Override //通过Geocoder获取地点的经纬度,然后发送Handler Message
public void run() {
try{
addressList = geocoder.getFromLocationName(location, 5);
uiCallback.sendEmptyMessage(0); //由于通过addressList对象共享结果,所以使用空消息即可
}catch(Exception e){
Log.e("WEI","ERROR: " + e.toString());
e.printStackTrace();
}
}
};
thread.start();
}
//(3)Handler位于主线程,故有关的消息处理在UI线程中进行
private Handler uiCallback= new Handler(){
@Override
public void handleMessage(Message msg) {
proDialog.dismiss(); //关闭进度框
int index = msg.what;
if(addressList != null && addressList.size() > index){ //找到地点则显示地图
double lat = addressList.get(index).getLatitude();
double lng = addressList.get(index).getLongitude();
String url = "http://api.map.baidu.com/staticimage?center=" +
lng + "," + lat + "&width=" + browser.getWidth()
+ "&height=" +browser.getHeight() + "&zoom=14";
browser.loadUrl(url);
}else{ //找不到地点则弹告警框,可以关闭测试机的网络来模拟该情况
Dialog foundNothingDlg = new AlertDialog.Builder(GeoTestBack.this)
.setIcon(0)
.setTitle("Fail to find location")
.setPositiveButton("OK", null)
.setMessage("Location not found....")
.create();
foundNothingDlg.show();
}
}
};
}
新小例子运行情况如下:
小例子代码在:Pro Android学习:location小例子
相关链接:我的Android开发相关文章