我已经坚持这个问题很长一段时间了。我正在开发一个在几个不同的活动中广泛使用位置的应用程序。我发现的每个示例都在每个Activity中使用单独的LocationListener。这在我的情况下是不可行的。
我想知道在多个活动中跟踪用户位置的最有效方法是什么。现在我已经创建了一个实现LocationListener的服务,并使用广播来更新Activity基类中的静态lat和long字段。这意味着该服务始终在运行,这并不理想。但是,如果我关闭服务并仅在需要时重新启动它,那么获得一个好位置需要时间。我需要Activity的onCreate()中的位置数据。如果我尝试在activity基类中实现它,它也是一样的。如果我经常在onResume / onCreate中注册监听器并在onPause()中取消注册,则开始接收更新需要花费太多时间。我还试图创建一个我可以绑定的服务,所以它只在我需要一个位置时启动。但是我遇到了同样的问题,绑定到服务并开始获取更新需要很长时间。
我现在使用的服务有效,但是从我读过的所有内容开始,我不应该使用持续运行的服务来处理这样的琐碎事情。但该应用程序的重点是根据用户的当前位置提供相关数据。所以我有一个只在后台运行的服务,并定期提供更新。导致我在这一点上重新检查设计的一个主要问题是,我最近发现,如果用户在没有打开GPS的情况下启动应用程序然后启用它,则不会调用onProviderEnabled()。在这种情况下,应用程序无法识别GPS已启用,因此它可以开始侦听更新。
我认为我从查看示例中了解了LocationManager和LocationListener,但我似乎无法将其应用于需要多个活动中的位置数据的情况。任何帮助或建议将不胜感激。
答案 0 :(得分:43)
我通常实现此要求的方式是使用绑定的Service实现,如SDK文档中Local Service Sample中的实现。显然,您熟悉服务的优势,只允许您创建一次所有位置代码。
通过Bindings访问服务允许服务启动和停止,因此当您的应用程序不在前台时它就不会运行(只要不再绑定活动就会死掉)。使IMO工作良好的关键是将onStart()
中的服务和onStop()
中的UNBIND绑定,因为当您从一个Activity移动到另一个Activity时,这两个调用会重叠(第二个活动在第一个Activity之前开始)一个停止)。这使得服务在应用程序内移动时不会死亡,只有当整个应用程序(或至少任何对位置感兴趣的部分)离开前台时服务才会死亡。
使用Bindings,您不必在Broadcast中传递Location数据,因为Activity可以直接在Service上调用方法来获取最新位置。但是,广播作为一种指示何时有新的更新可用的方法仍然是有利的......但这只会成为监听活动的通知,以便在服务上调用getLocation()
方法。
我的0.02美元。希望有帮助!
答案 1 :(得分:17)
我遇到了同样的问题,我试图用Devunwired的好答案来解决它,但我遇到了一些麻烦。我找不到停止服务的方法,当我完成我的应用程序时,GPS模块仍在运行。所以我找到了另一种方式:
我写了一个GPS.java类:
public class GPS {
private IGPSActivity main;
// Helper for GPS-Position
private LocationListener mlocListener;
private LocationManager mlocManager;
private boolean isRunning;
public GPS(IGPSActivity main) {
this.main = main;
// GPS Position
mlocManager = (LocationManager) ((Activity) this.main).getSystemService(Context.LOCATION_SERVICE);
mlocListener = new MyLocationListener();
mlocManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, mlocListener);
// GPS Position END
this.isRunning = true;
}
public void stopGPS() {
if(isRunning) {
mlocManager.removeUpdates(mlocListener);
this.isRunning = false;
}
}
public void resumeGPS() {
mlocManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, mlocListener);
this.isRunning = true;
}
public boolean isRunning() {
return this.isRunning;
}
public class MyLocationListener implements LocationListener {
private final String TAG = MyLocationListener.class.getSimpleName();
@Override
public void onLocationChanged(Location loc) {
GPS.this.main.locationChanged(loc.getLongitude(), loc.getLatitude());
}
@Override
public void onProviderDisabled(String provider) {
GPS.this.main.displayGPSSettingsDialog();
}
@Override
public void onProviderEnabled(String provider) {
}
@Override
public void onStatusChanged(String provider, int status, Bundle extras) {
}
}
}
此类用于需要GPS坐标的每个Activity。每个Activity都必须实现以下接口(通信所需):
public interface IGPSActivity {
public void locationChanged(double longitude, double latitude);
public void displayGPSSettingsDialog();
}
现在我的主要活动看起来像这样:
public class MainActivity extends Activity implements IGPSActivity {
private GPS gps;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
gps = new GPS(this);
}
@Override
protected void onResume() {
if(!gps.isRunning()) gps.resumeGPS();
super.onResume();
}
@Override
protected void onStop() {
gps.stopGPS();
super.onStop();
}
public void locationChanged(double longitude, double latitude) {
Log.d(TAG, "Main-Longitude: " + longitude);
Log.d(TAG, "Main-Latitude: " + latitude);
}
@Override
public void displayGPSSettingsDialog() {
Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
startActivity(intent);
}
}
和第二个这样的:
public class TEST4GPS extends Activity implements IGPSActivity{
private GPS gps;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.gps = new GPS(this);
}
@Override
public void locationChanged(double longitude, double latitude) {
Log.d("TEST", "Test-Longitude: " + longitude);
Log.d("TEST", "Test-Latitude: " + latitude);
}
@Override
protected void onResume() {
if(!gps.isRunning()) gps.resumeGPS();
super. onResume();
}
@Override
protected void onStop() {
gps.stopGPS();
super.onStop();
}
@Override
public void displayGPSSettingsDialog() {
Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
startActivity(intent);
}
}
它不如Devunwired的解决方案那么漂亮,但它对我有用。 CYA
答案 2 :(得分:0)
你可以让你的服务写下你的lat&对sqlite数据库的长连接更改,因为您没有服务绑定开销,并且您的所有活动都可以访问您的坐标。
也许在您的主要活动中,您可以检查GPS状态,如果它已关闭,您可以提示用户启用它。启用GPS后,请启动您的服务。
答案 3 :(得分:-1)
这是一种非常简单明了的方法:
在您的主要活动中:
private boolean mFinish;
@Override
public void onBackPressed() {
mFinish = true;
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mFinish = false;
...
}
@Override
public void onPause(){
super.onPause();
if (mFinish) {
// remove updates here
mLocationManager.removeUpdates(mLocationListener);
}
}
如果您在主要活动中按“返回”,则此选项仅会删除更新侦听器,否则将继续保留。
这不是最好的方法,但它是一个简单的复制粘贴解决方案。
如果位置监听器已经在运行(例如在屏幕上旋转),请确保不要呼叫位置监听器,否则您最终会在后台运行多个监听器。