Reputation: 245
I have a map activity which also has an EditText on top of it and I want to show the changing address in that EditText whenever there's a drag on the map. I am currently using Geocoder class to retrieve address based on the coordinates provided by the map. But this way is causing a lot of lag in the fluent dragging motion of the map. Is there a better way to retrieve address or a more efficient way to use Geocoder class? Right now, I have implemented the getAddress() method inside the OnCameraChangeListener event of my map. Here is the code.
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);
}
});
I have seen another app implemented where the address searched was at the end of the map drag and there was no lag in the map's motion.
Upvotes: 2
Views: 1155
Reputation: 768
The Geocoder$getFromLocation()
is a blocking call, which means it will freeze the UI thread till the api returns the address. The only solution is to run this call on a background thread.
There are two ways you can achieve this:
Intent Service
. You can find the details on how to here. Personally, I feel this is overkill and very complicated.AsyncTask
. See this to get a general idea and implement according to your needs.Also, if you are using Rx, you can start a new observable from the geocoder and observe on a different thread and subscribe on the main thread.
UPDATE: I pulled this code from one of my old projects, see if it helps.
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;
}
}
The AsyncTask implementation
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);
}
}
Calling the method when location changes:
new AsyncGeocoder().execute(new AsyncGeocoderObject(
new Geocoder(this),
location,
locationTV
));
Hope this helps!
UPDATE 2:
Notes on how to immplement the above:
AsyncGeocoderObject
and copy the contentsAsyncGeocoder
and copy the contents.Now, say you want to get the users location in MainActivity
and display the address in a textview, say locationTV
. After instantiating the textview, create a new object of AsyncGeocoder
and pass in the parameters. eg:
// 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
));
Also, if you dont have a location object, create on using the latitude and longitude you have. See this post for how to.
Hope this helps you!
Upvotes: 1