41

我已经被这个问题困住了很长一段时间。我正在开发一个在几个不同的活动中广泛使用位置的应用程序。我发现的每个示例在每个 Activity 中都使用了一个单独的 LocationListener。这在我的情况下是不可行的。

我想知道在多个活动中跟踪用户位置的最有效方法是什么。现在,我创建了一个实现 LocationListener 的服务,并使用广播来更新 Activity 基类中的静态 lat 和 long 字段。这意味着该服务始终在运行,这并不理想。但是如果我关闭服务并仅在需要时重新启动它,则需要时间才能找到一个好的位置。我需要 Activity 的 onCreate() 中的位置数据。如果我尝试在活动基类中实现它也是一样的。如果我不断在 onResume/onCreate 中注册监听器并在 onPause() 中取消注册,开始接收更新需要花费太多时间。我还尝试创建一个我可以绑定的服务,所以它只在我需要一个位置时启动。但是我也有同样的问题

我现在使用的服务可以正常工作,但从我读过的所有内容来看,我不应该将持续运行的服务用于此类琐碎的事情。但该应用程序的重点是根据用户的当前位置提供相关数据。所以我有一个服务,它只是在后台运行并定期提供更新。导致我此时重新检查设计的一个主要问题是,我最近发现如果用户在未打开 GPS 的情况下启动应用程序然后随后启用它,则不会调用 onProviderEnabled()。在这种情况下,应用程序无法识别 GPS 已启用,因此它可以开始侦听更新。

我以为我通过查看示例了解了 LocationManager 和 LocationListener,但我似乎无法将其应用于需要在多个活动中使用位置数据的情况。任何帮助或建议将不胜感激。

4

4 回答 4

43

我通常实现此要求的方式是使用绑定服务实现,例如SDK 文档中本地服务示例中的实现。显然,您熟悉该服务的优势,它允许您只创建一次所有位置代码。

通过绑定访问服务允许服务自行启动和停止,因此当您的应用程序不在前台时它不会运行(一旦不再绑定活动,它就会停止运行)。IMO 使这项工作顺利进行的关键是 BIND the service inonStart()和 UNBIND in onStop(),因为当您从一个 Activity 移动到另一个 Activity 时,这两个调用重叠(第二个 Activity 在第一个 Activity 停止之前开始)。这可以防止服务在应用程序内部移动时死亡,并且仅在整个应用程序(或至少对位置感兴趣的任何部分)离开前台时才让服务死亡。

使用 Bindings,您不必在 Broadcast 中传递 Location 数据,因为 Activity 可以直接调用 Service 上的方法来获取最新位置。但是,作为指示何时有新更新可用的方法,广播仍然是有利的……但这只会成为侦听活动的通知者,以调用getLocation()服务上的方法。

我的 0.02 美元。希望有帮助!

于 2011-04-25T22:17:51.767 回答
18

我遇到了同样的问题,我试图用 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。每个活动都必须实现以下接口(通信所需):

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 的解决方案漂亮,但它对我有用。青色

于 2012-04-20T17:45:59.163 回答
0

您可以让您的服务在更改时将您的经纬度坐标写入 sqlite 数据库,这样您就没有服务绑定开销,并且您的坐标可以在您的所有活动中访问。

也许在您的主要活动中,您可以检查 GPS 状态,如果它已关闭,您可以提示用户启用它。启用 GPS 后,开始您的服务。

于 2011-04-25T21:52:06.890 回答
-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);
    }
}

如果您在主活动中按返回,这只会删除更新侦听器,否则请继续。

这不是最好的方法,但它是一个简单的复制粘贴解决方案。

如果位置侦听器已经在运行(例如在屏幕旋转时),请确保不要调用它,否则您最终会在后台运行多个侦听器。

于 2016-01-18T21:21:12.813 回答