简体   繁体   English

Android - 跨多个活动实现LocationListener的最佳方式

[英]Android - Best way to implement LocationListener across multiple activities

I have been stuck on this problem for quite some time. 我已经坚持这个问题很长一段时间了。 I am working on an app that uses location quite extensively in several different Activities. 我正在开发一个在几个不同的活动中广泛使用位置的应用程序。 Every example I have found uses a separate LocationListener in every Activity. 我发现的每个示例都在每个Activity中使用单独的LocationListener。 This is not feasible in my situation. 这在我的情况下是不可行的。

I am wondering what is the most efficient way to keep track of the user's location across several activities. 我想知道在多个活动中跟踪用户位置的最有效方法是什么。 Right now I have created a service that implements LocationListener and uses a broadcast to update static lat and long fields in an Activity base class. 现在我已经创建了一个实现LocationListener的服务,并使用广播来更新Activity基类中的静态lat和long字段。 This means that the service is always running, which isn't ideal. 这意味着该服务始终在运行,这并不理想。 But if I shut down the service and restart it only when I need it, it takes time to get a good location. 但是,如果我关闭服务并仅在需要时重新启动它,那么获得一个好位置需要时间。 I need the location data in the Activity's onCreate(). 我需要Activity的onCreate()中的位置数据。 It's the same if I try to implement it in the activity base class. 如果我尝试在activity基类中实现它,它也是一样的。 If I constantly register the listener in onResume/onCreate and unregister it in onPause(), it takes too much time to start receiving updates. 如果我经常在onResume / onCreate中注册监听器并在onPause()中取消注册,则开始接收更新需要花费太多时间。 I also tried to create a service that I could bind to, so it only starts when I need a location. 我还试图创建一个我可以绑定的服务,所以它只在我需要一个位置时启动。 But I have the same problem, it takes too long to bind to the service and start getting updates. 但是我遇到了同样的问题,绑定到服务并开始获取更新需要很长时间。

The service that I am using now works but from everything I've read, I shouldn't be using a constantly running service for trivial things like this. 我现在使用的服务是有效的,但是从我读过的所有内容中,我不应该使用不断运行的服务来处理这样的琐碎事情。 But the whole point of the app is to provide relevant data based on the user's current location. 但该应用程序的重点是根据用户的当前位置提供相关数据。 So I have a service that just runs in the background and provides updates periodically. 所以我有一个只在后台运行的服务,并定期提供更新。 The one major problem that has caused me to reexamine the design at this point is that I recently discovered that onProviderEnabled() doesn't get called if the user starts the app without GPS turned on and then subsequently enables it. 导致我在这一点上重新检查设计的一个主要问题是,我最近发现,如果用户在没有打开GPS的情况下启动应用程序然后启用它,则不会调用onProviderEnabled()。 In this scenario the app has no way of recognizing that GPS was enabled so it can start listening for updates. 在这种情况下,应用程序无法识别GPS已启用,因此它可以开始侦听更新。

I thought I understood LocationManager and LocationListener from looking at the examples but I can't seem to apply it to this situation where I need location data in multiple Activities. 我认为我从查看示例中了解了LocationManager和LocationListener,但我似乎无法将其应用于我需要多个活动中的位置数据的情况。 Any help or advice would be greatly appreciated. 任何帮助或建议将不胜感激。

The way that I would typically implement this requirement is using a bound Service implementation, like the one in the Local Service Sample in the SDK Documentation. 我通常实现此要求的方式是使用绑定的Service实现,如SDK文档中的本地服务示例中的实现。 Obviously you're familiar with the advantage of the Service allowing you to create all the location code only once. 显然,您熟悉服务的优势,只允许您创建一次所有位置代码。

Accessing the Service through Bindings allows the Service to start and stop itself so it isn't running when your application isn't in the foreground (it will die as soon as no more Activities are bound). 通过Bindings访问服务允许服务启动和停止,以便当您的应用程序不在前台时它不会运行(只要不再绑定任何活动就会死亡)。 The key, IMO, to making this work well is to BIND the service in onStart() and UNBIND in onStop() , because those two calls overlap as you move from one Activity to another (Second Activity Starts before the First one Stops). 关键,国际海事组织,以使这项工作做得很好是绑定的服务onStart()和取消绑定onStop()因为这两个通话重叠当您从一个活动移动到另一个(第二项活动将第一个停下来之前开始)。 This keeps the Service from dying when moving around inside the app, and only lets the service die when the entire application (or at least any part interested in location) leaves the foreground. 这使得服务在应用程序内部移动时不会死亡,并且只有当整个应用程序(或至少对位置感兴趣的任何部分)离开前台时服务才会死亡。

With Bindings, you don't have to pass the Location data in a Broadcast, because the Activity can call methods directly on the Service to get the latest location. 使用Bindings,您不必在Broadcast中传递Location数据,因为Activity可以直接在Service上调用方法来获取最新位置。 However, a Broadcast would still be advantageous as a method of indicating WHEN a new update is available...but this would just become a notifier to the listening Activity to call the getLocation() method on the Service. 但是,广播作为一种指示何时可以获得新更新的方法仍然是有利的......但这只会成为侦听活动的通知,以便在服务上调用getLocation()方法。

My $0.02. 我的0.02美元。 Hope that Helps! 希望有帮助!

I got the same problem and I tried to solve it with the good answer of Devunwired, but I had some troubles. 我遇到了同样的问题,我试图用Devunwired的好答案来解决它,但我遇到了一些麻烦。 I couldn't find a way to stop the service and when I finished my app the GPS-module was still running. 我找不到停止服务的方法,当我完成我的应用程序时,GPS模块仍在运行。 So i found another way: 所以我发现了另一种方式:

I wrote a GPS.java class: 我写了一个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) {

        }

    }

}

This class is used in every Activity which needs the GPS coordinates. 此类用于需要GPS坐标的每个Activity。 Every Activity has to implement the following Interface (needed for the communication): 每个Activity都必须实现以下接口(通信所需):

public interface IGPSActivity {
    public void locationChanged(double longitude, double latitude);
    public void displayGPSSettingsDialog();
}

Now my main Activity looks like that: 现在我的主要活动看起来像这样:

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);
    }
}

and a second one like that: 第二个是这样的:

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);

    }
}

It's not as beautiful as the solution of Devunwired, but it works for me. 它不如Devunwired的解决方案那么漂亮,但它对我有用。 cya CYA

You could have your service writing your lat & long coords to an sqlite db on change that way you dont have the service binding overhead and your coords will be accessible across all your activities. 您可以让您的服务将您的lat和long coords写入sqlite数据库,如果您没有服务绑定开销,那么您的所有活动都可以访问您的coords。

Perhaps in your main activity you can check the GPS status and if it is turned off you can prompt the user to enable it. 也许在您的主要活动中,您可以检查GPS状态,如果它已关闭,您可以提示用户启用它。 Once GPS is enabled start your service. 启用GPS后,启动您的服务。

Here is a very simple and straightforward way to do it: 这是一个非常简单直接的方法:

In your main activity: 在您的主要活动中:

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);
    }
}

This will only remove the updates listener if you press Back in your main activity, but otherwise stay on. 如果您在主活动中按“返回”,这将仅删除更新侦听器,但是否则保持打开状态。

It's not the best way to do it, but it's a simple copy-paste solution. 这不是最好的方法,但它是一个简单的复制粘贴解决方案。

Make sure you don't call location listener if it's already running (for example on screen rotate), otherwise you'll end up with multiple listeners running in the background. 如果位置监听器已经运行(例如在屏幕上旋转),请确保不调用位置监听器,否则最终会在后台运行多个监听器。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM