是否有必要在单独的线程中查找获取位置?
我担心在主线程上查找位置信息(使用反向地理编码)会减慢我的用户界面。为了解决这个问题,我将信息放入 AsyncTask (下面的代码)现在我想添加位置侦听器,我遇到了各种各样的问题。
我做了一些研究,现在想知道...是否有必要将位置代码放入 AsyncTask 中?也许 Android 只是“自然地”异步查找位置信息?
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 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 below) 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]);
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我进行了一些快速搜索,没有看到任何对运行异步的 LocationManager 的具体引用,但我的假设是它确实如此或其调度方式不会影响 UI 性能,因为它是一项系统服务。
根据经验,我在主线程上获取位置并将其显示给用户没有任何问题。事实上,我计算了列表中大约 100 个项目的距离,UI 没有明显变慢。不过,我认为后一个计算应该考虑 AsyncTask,因为它很容易影响性能。但也要注意 AsyncTask 任务的持续时间和 LocationManager 位置更新的更新间隔。
根据每次调用 updateWithANewLocation 所需的时间,您可能需要考虑将其放在后台任务上,并将 LocationManager 保留在主线程上。
我假设您遇到的问题是 LocationManager 上的事件处理。以下内容应该可以深入了解问题的这一部分:
http://developer.android.com/reference/android/location/LocationManager.html#requestLocationUpdates%28java.lang.String,%20long,%20float,%20android.location.LocationListener%29
http://developer.android.com/reference/android/os/Looper.html 基本上,
当您的 LocationAsyncTask 完成执行时,它就消失了,因此事件回调发生在不再存在的线程上。 Looper 将启动一个消息循环来接受这些 LocationManager 事件。
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
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.
iOS SDK 的核心位置提供了一个
CLLocationManager
对象,其中包含名为startUpdatingLocation
和startMonitoringSignificantLocationChanges
的实例方法,这两个方法都是异步工作的。调用其中之一后,您只需实现回调locationManager:didUpdateToLocation:fromLocation
来处理位置更新。我敢打赌 Android 也会做类似的事情。如果没有,请提交错误。Core Location of the iOS SDK provides a
CLLocationManager
object with instance methods calledstartUpdatingLocation
andstartMonitoringSignificantLocationChanges
that both work asynchronously. After calling one of those, you just implement the callbacklocationManager:didUpdateToLocation:fromLocation
to handle the location updates. I bet Android does something similar. If not, file a bug.