【问题标题】:Using Geocoder to retrieve address based on Latitude and Longitude causes lag. Android使用地理编码器根据纬度和经度检索地址会导致延迟。安卓
【发布时间】:2016-11-20 15:15:24
【问题描述】:

我有一个地图活动,上面还有一个 EditText,我想在地图上有拖动时在该 EditText 中显示更改的地址。我目前正在使用 Geocoder 类根据地图提供的坐标检索地址。但是这种方式在地图的流畅拖动中造成了很大的延迟。有没有更好的方法来检索地址或更有效的方法来使用 Geocoder 类?现在,我已经在我的地图的 OnCameraChangeListener 事件中实现了 getAddress() 方法。这是代码。

mMap.setOnCameraChangeListener(new GoogleMap.OnCameraChangeListener() {
            @Override
            public void onCameraChange(CameraPosition cameraPosition) {
                double latitude=mMap.getCameraPosition().target.latitude;
                double longitude=mMap.getCameraPosition().target.longitude;
                String _Location="";
                Geocoder geocoder = new Geocoder(getApplicationContext(), Locale.getDefault());
                try {
                    List<Address> listAddresses = geocoder.getFromLocation(latitude, longitude, 1);
                    if(null!=listAddresses&&listAddresses.size()>0){
                        _Location = listAddresses.get(0).getAddressLine(0);
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
                EditText addressTxt=(EditText) findViewById(R.id.search_address_txt);
                addressTxt.setText(_Location);
            }
        });

我看到另一个应用程序实现了,其中搜索的地址位于地图拖动的末尾,并且地图的运动没有滞后。

【问题讨论】:

    标签: java android google-maps google-maps-api-3


    【解决方案1】:

    Geocoder$getFromLocation() 是一个阻塞调用,这意味着它将冻结 UI 线程,直到 api 返回地址。唯一的解决方案是在后台线程上运行此调用。

    有两种方法可以实现:

    1. 使用 Google 推荐的方式 - 使用 Intent Service。您可以找到有关如何here 的详细信息。就我个人而言,我觉得这太过分了,而且非常复杂。
    2. 使用AsyncTask。请参阅this 了解总体思路并根据您的需要实施。

    另外,如果您使用的是 Rx,您可以从地理编码器中启动一个新的 observable,然后在不同的线程上观察并在主线程上订阅。

    更新:我从我的一个旧项目中提取了这段代码,看看它是否有帮助。

    AsyncGeocoderObject.java // object to pass to asynctask
    
    public class AsyncGeocoderObject {
    
        public Location location; // location to get address from
        Geocoder geocoder; // the geocoder
        TextView textView; // textview to update text
    
        public AsyncGeocoderObject(Geocoder geocoder, Location location, TextView textView) {
            this.geocoder = geocoder;
            this.location = location;
            this.textView = textView;
        }
    }
    


    AsyncTask 实现

    public class AsyncGeocoder extends AsyncTask<AsyncGeocoderObject, Void, List<Address>> {
    
    private TextView textView;
    
    @Override
    protected List<Address> doInBackground(AsyncGeocoderObject... asyncGeocoderObjects) {
        List<Address> addresses = null;
        AsyncGeocoderObject asyncGeocoderObject = asyncGeocoderObjects[0];
        textView = asyncGeocoderObject.textView;
        try {
            addresses = asyncGeocoderObject.geocoder.getFromLocation(asyncGeocoderObject.location.getLatitude(),
                    asyncGeocoderObject.location.getLongitude(), 1);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return addresses;
    }
    
    @Override
    protected void onPostExecute(List<Address> addresses) {
        Log.v("onPostExecute", "location: " + addresses);
        String address;
        if (addresses != null)
            address = addresses.get(0).getLocality() + ", " + addresses.get(0).getCountryName();
        else address = "Service unavailable.";
        textView.setText(address);
    }
    }
    

    位置改变时调用方法:

    new AsyncGeocoder().execute(new AsyncGeocoderObject(
                    new Geocoder(this),
                    location,
                    locationTV
            ));
    

    希望这会有所帮助!

    更新 2:
    关于如何实现上述内容的说明:

    1. 新建类AsyncGeocoderObject并复制内容
    2. 创建另一个类(可以是活动中的子类或不同的 java 文件中)AsyncGeocoder 并复制内容。
    3. 现在,假设您想在MainActivity 中获取用户位置并在文本视图中显示地址,例如locationTV。实例化textview后,新建一个AsyncGeocoder的对象,并传入参数。例如:

      // in onCreate()
      new AsyncGeocoder().execute(new AsyncGeocoderObject(
              new Geocoder(this), // the geocoder object to get address
              location, // location object, 
              locationTV // the textview to set address on
      )); 
      

      另外,如果您没有位置对象,请使用您拥有的纬度和经度进行创建。 See this post for how to.

    希望对您有所帮助!

    【讨论】:

    • 抱歉回复晚了。感谢帮助。但是你能指导我把代码放在哪里吗?在我需要获取地址的活动中?还是我要创建一个新的 java 类?
    • @RehanYousaf 添加了更多细节。看看他们是否有帮助
    • 我想使用 LatLng,所以我相应地更改了您提供的代码中的参数。谢谢!它现在可以工作了。
    • 很高兴我能帮上忙! :)
    猜你喜欢
    • 1970-01-01
    • 2014-01-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多