I was worried that finding location info (with reverse geocoding) on the main thread would slow up my UI. To solve this problem I put the info into a AsyncTask (code b开发者_StackOverflow社区elow) Now I want to add location listeners, I am having all sorts of problems.
Ive done a bit of research and now wonder... Is it even necessary to put location code in an AsyncTask? Maybe Android just "naturally" finds location info asynchronously?
public class LocationAsyncTask extends AsyncTask<Void, String, String> {
@Override protected void onPostExecute(String result) {
// TODO Auto-generated method stub
tvLocation.setText(result);
}
@Override
protected void onPreExecute() {
// TODO Auto-generated method stub
tvLocation.setText("Finding current location");
}
@Override
protected String doInBackground(Void... params) {
// TODO Auto-generated method stub
LocationManager locationManager;
String context = Context.LOCATION_SERVICE;
locationManager = (LocationManager)getSystemService(context);
Criteria criteria = new Criteria();
criteria.setAccuracy(Criteria.ACCURACY_FINE);
criteria.setAltitudeRequired(false);
criteria.setBearingRequired(false);
criteria.setCostAllowed(true);
criteria.setPowerRequirement(Criteria.POWER_LOW);
String provider = locationManager.getBestProvider(criteria, true);
Location location =locationManager.getLastKnownLocation(provider);
String strUpdateResult = updateWithANewLocation(location);
//locationManager.requestLocationUpdates(provider, 1000, 10, locationListener);
return strUpdateResult;
}
private String updateWithANewLocation(Location location) {
// TODO Auto-generated method stub
StringBuilder sbLocation = new StringBuilder();
String strLocation = new String();
TextView myLocationText;
String addressString = "No address found";
String latLongString = "";
//If there is a location
if (location!= null) {
double latitude = location.getLatitude();
double longitude = location.getLongitude();
double altitude = location.getAltitude();
float accuracy = location.getAccuracy();
float bearing = location.getBearing();
long time = location.getTime();
float speed = location.getSpeed();
String prov = location.getProvider();
strLocation = "Latitude: " + latitude + "\nLongitude: " + longitude + "\n" ;
publishProgress(strLocation);
Geocoder gc = new Geocoder(LateRunner.this, Locale.getDefault());
try {
List<Address> addresses = gc.getFromLocation(latitude, longitude, 1);
//if location and then address is found
if (addresses.size() > 0 ) {
Address address = addresses.get(0);
for (int i=0; i <address.getMaxAddressLineIndex(); i++) {
sbLocation.append(address.getAddressLine(i)).append("\n");
}
strLocation= sbLocation.toString();
publishProgress(strLocation);
}
//if location but no address
else {
strLocation = "Latitude: " + latitude + "\nLongitude: " + longitude + "\n";
publishProgress(strLocation);
} //end try
} catch (IOException e) {
strLocation = "Latitude: " + latitude + "\nLongitude: " + longitude + "\n";
publishProgress(strLocation);
}//end catch
}
//If no location found
else {
strLocation = "Unable to find location. ";
publishProgress(strLocation);
}
return strLocation;
}// end updateWithANewLocation()
@Override protected void onProgressUpdate(String... result) {
// TODO Auto-generated method stub
tvLocation.setText(result[0]);
}
}
I did some quick searching and didn't see any specific references to the LocationManager running async, but my assumption is that it does or its scheduled in a way that doesn't impact UI performance since it's a system service.
From experience I have had no issue getting the location on the main thread and displaying it back to the user. In fact I calculate the distance away for about 100 items in a list without a noticeable slowdown on the UI. The latter calc though is where I'd say you should think about AsyncTask, since it can easily impact performance. Though also be careful of how long your AsyncTask tasks and the update interval of the LocationManager location updates.
Depending on how long each call to updateWithANewLocation takes you might want to think about putting that on a background task and leave the LocationManager on the Main thread.
I'm assuming where you're having an issue is with the event handling on the LocationManager. The following should give some insight into that part of the issue:
http://developer.android.com/reference/android/location/LocationManager.html#requestLocationUpdates%28java.lang.String,%20long,%20float,%20android.location.LocationListener%29
The calling thread must be a Looper thread such as the main thread of the calling Activity.
http://developer.android.com/reference/android/os/Looper.html
Basically when your LocationAsyncTask finished executing, its gone, so the event callbacks are happening to a thread that doesn't exist anymore. The Looper would initiate a message loop to accept those LocationManager events.
Core Location of the iOS SDK provides a CLLocationManager
object with instance methods called startUpdatingLocation
and startMonitoringSignificantLocationChanges
that both work asynchronously. After calling one of those, you just implement the callback locationManager:didUpdateToLocation:fromLocation
to handle the location updates. I bet Android does something similar. If not, file a bug.
精彩评论