【问题标题】:Android - Best way to implement LocationListener across multiple activitiesAndroid - 在多个活动中实现 LocationListener 的最佳方式
【发布时间】:2011-04-25 21:41:18
【问题描述】:

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

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

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

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

【问题讨论】:

    标签: android locationlistener


    【解决方案1】:

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

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

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

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

    【讨论】:

    • 我以前一直在这条路上,但我不知道 onStart 和 onStop 像那样重叠。这对我很有吸引力,我会试试这个,让你知道我明天想出什么。谢谢!
    • 只是想知道,这将如何与关闭屏幕一起工作?在 onResume() 上绑定服务并在 onPause() 上取消绑定以在屏幕打开/关闭时打开/关闭它以及在活动切换时工作是否明智?
    • @Grantland 有效点,因为 Activity 仍然是服务将存在的前台。如果服务需要在这些情况下自我节流,我会保持绑定不变,但让它为Intent.ACTION_SCREEN_ONIntent.ACTION_SCREEN_OFF 注册一个BroadcastReceiver 以关闭GPS 等重型组件。将绑定机制移动到 onPause()/onResume() 会导致服务在整个应用程序使用过程中经常停止/重新启动,因为这些回调永远不会重叠,从而让服务经常陷入未绑定状态。
    • 很好的解决方案。我认为您需要像bindService(intent, mServiceConn, BIND_AUTO_CREATE ) 那样与 BIND_AUTO_CREATE 绑定,有人可以确认吗?
    【解决方案2】:

    我遇到了同样的问题,我试图用 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 的解决方案漂亮,但它对我有用。 赛亚

    【讨论】:

    • 喜欢您的解决方案!我做了一些改进并且工作正常!谢谢。
    • @Spipau,我喜欢你的回答。我试过了,但它对我不起作用。你有没有机会看看我的代码,看看你是否能弄清楚我做错了什么? stackoverflow.com/questions/29771717/…
    • @MrGibbage 对不起,但我必须重新创建整个事情。我的答案现在已经 3 年了,如果我必须再次在我的应用程序中实现全球 GPS 信号,它看起来会完全不同。将跟踪代码放入您的应用程序并使用 LocalBroadcastManager 将位置发送到您选择的活动/片段。 developer.android.com/reference/android/support/v4/content/…
    • 它解决了我在多个活动中获取位置的问题。虽然我不得不从 gms 位置切换到 android 位置。
    【解决方案3】:

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

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

    【讨论】:

      【解决方案4】:

      这是一个非常简单直接的方法:

      在你的主要活动中:

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

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

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

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-11-23
        • 1970-01-01
        • 1970-01-01
        • 2020-06-17
        • 2011-02-02
        • 1970-01-01
        相关资源
        最近更新 更多