Pro Android学习笔记(一一五):Location(1):Geocoder

文章转载只能用于非商业性质,且不能带有虚拟货币、积分、注册等附加条件。转载须注明出处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

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

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很有可能有反应,实验结果如下:

Pro Android学习笔记(一一五):Location(1):Geocoder_第1张图片

从结果可以看到,给出的地理信息有很多,并不只是经纬度,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

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();
    }       
}

执行情况如下:

Pro Android学习笔记(一一五):Location(1):Geocoder_第2张图片

后台线程中使用Geocoder

无论是经纬度查地址,还是地址查经纬度,在测试中,我们会发现有时结果返回有明显的时延,一方面和云服务的处理能力有关,而更多的和移动网络连接有关,当时延超过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

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(1):Geocoder_第3张图片

小例子代码在:Pro Android学习:location小例子

相关链接:我的Android开发相关文章

你可能感兴趣的:(Android)