【问题标题】:What can I use in Application that is similar to Activity.onPause()我可以在类似于 Activity.onPause() 的应用程序中使用什么
【发布时间】:2015-01-06 20:38:13
【问题描述】:

我正在寻找一些类似于 Activity.onPause() 的回调,但更通用(我没有 Activity,因为此代码在后台运行)在我的应用程序被杀死之前调用。我不会尝试 Application.onLowMemory() ,因为根据文档,它并不总是被调用[我的意思是当我通过返回或主页按钮退出某些活动时,我的应用程序也可能(而且我知道有时会)被杀死]。

我的应用程序中有一个 LocationListener 类,它进行了一些非常繁重的计算,因此我使用了一些“缓存”或优化。只有当位置发生很大变化或经过足够的时间时,我才会进行繁重的计算。

我注意到,大多数时候,即使我不移动手机,我的繁重计算代码也会一次又一次地被调用。事实证明,这是因为 oldLocation 为空(我的应用程序被 android 杀死)该应用程序工作,因为它被 LocationService 唤醒,但它“忘记”了缓存的 lastLocation (=null)。所以我添加了 saveLastLocation() 这确实有帮助,但我试图找出最好的调用位置。一开始我从 finalize() 中调用它,但它从未被调用过。似乎android“太快”地杀死了我的应用程序,以至于无法调用它。然后我把它移到了它现在的位置,就在繁重的计算之后。

我想知道是否有一种方法,类似于我在 Activity 中使用 onPause() 调用 saveLastLocation 并使用 onResume 调用 loadLastLocation 的理想方法。

我将 MyLocationListener 的实例作为 MyApplication 的静态成员(用于缓存目的)

class MyLocationListener implements LocationListener {
    private static MyLocationListener instance;
    private Location lastLocation;

    public static MyLocationListener getInstance() {
        if (null == instance) {
            instance = new MyLocationListener();
        }
        return instance;
    }

    private MyLocationListener() {
        loadLastLocation();
    }

    @Override
    public synchronized void onLocationChanged(final Location location) {
        if (null == lastLocation || lastLocation.distanceTo(location) > MIN_LOCATION_CHANGE_DISTANCE
                    || getElapsedNanoSec(location) - getElapsedNanoSec(lastLocation) > MIN_LOCATION_CHANGE_NANOSEC) {
            // Just to see how many times we enter the heavy calculations
            Toast.makeText(MyApp.getContext(), "old: " + lastLocation + "new: " + location, Toast.LENGTH_LONG).show();

            // do the heavy calculations

            lastLocation = location;

            // Is there a better way to call saveLastLocation???
            saveLastLocation();
        }
    }

    private synchronized void saveLastLocation() {
        final SharedPreferences sharedPreferences = getSharedPreferences();
        SharedPreferences.Editor editor = sharedPreferences.edit();

        if (null != lastLocation) {
            editor.putString(PREF_LAST_LOCATION_PROVIDER, lastLocation.getProvider());
            editor.putLong(PREF_LAST_LOCATION_ELAPSED_REALTIME, getElapsedNanoSec(lastLocation));
            putDouble(editor, PREF_LAST_LOCATION_LATITUDE, lastLocation.getLatitude());
            putDouble(editor, PREF_LAST_LOCATION_LONGITUDE, lastLocation.getLongitude());
            editor.apply();
        }
    }

    private synchronized void loadLastLocation() {
        final SharedPreferences sharedPreferences = getSharedPreferences();
        final String provider = sharedPreferences.getString(PREF_LAST_LOCATION_PROVIDER, null);
        if (null != provider) {
            final long elapsed = sharedPreferences.getLong(PREF_LAST_LOCATION_ELAPSED_REALTIME, Long.MIN_VALUE);
            final double latitude = getDouble(sharedPreferences, PREF_LAST_LOCATION_LATITUDE, Double.MIN_VALUE);
            final double longitude = getDouble(sharedPreferences, PREF_LAST_LOCATION_LONGITUDE, Double.MIN_VALUE);
            if (null == lastLocation) {
                lastLocation = new Location(provider);
            } else {
                lastLocation.setProvider(provider);
            }
            setElapsedNanoSec(lastLocation, elapsed);
            lastLocation.setLatitude(latitude);
            lastLocation.setLongitude(longitude);
        }
    }

    private long getElapsedNanoSec(final Location location) {
        long elapsed;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
            elapsed = location.getElapsedRealtimeNanos();
        } else {
            elapsed = location.getTime() * 1000;
        }
        return elapsed;
    }
}

澄清一下:谷歌播放服务没有直接调用 MyLocationListener,我有另一个“真实”的 LocationListener 正在被调用,我从它的 onLocationChanged 调用 MyLocationListener.getInstance().onLocationChanged(location) [我这样做的原因这是我在代码中的许多地方使用大量计算的结果(通过调用此处未提供的其他函数),我希望它尽可能多地缓存]

【问题讨论】:

  • 繁重的计算是依赖旧位置还是只用于确定距离变化?
  • 只用于优化,不做繁重的计算。计算本身只使用当前位置(除了我打印“你从 移动到 ”的日志,但可以忽略它。

标签: android caching sharedpreferences onpause


【解决方案1】:

如果您使用的是新的FusedLocationProviderApi(它替换了 Google Play 服务 6.5 中的 LocationClient),那么您可以将 smallest displacement 设置为您的 LocationRequest 的一部分,这将确保您只会收到回调如果位置的变化超过了您的最小位移 - 这可以确保您每次收到回调时都能进行繁重的计算。

如果您确实还需要在一定时间后重新计算,您可以使用AlarmManager 设置一个警报,作为收到的每个位置更新的超时机制(并取消先前设置的警报),这会触发您的重如果没有位置更新,计算方法,使用FusedLocationApi.getLastLocation()作为当前位置(如果你愿意,也可以使用缓存值)。

注意,FusedLocationProviderApi 还提供了一个 requestLocationupdates() 方法,该方法采用 PendingIntent - 这非常适合不希望或需要维护持续运行的侦听器但希望触发短时间运行的处理程序的后台服务(IntentService 非常适合)响应事件。这可确保您的应用程序始终收到更新,即使 Android 停止了该应用程序。

【讨论】:

  • 其实我已经在使用 FusedLocationProvider 了。也许我只需要添加最小位移并微调其他请求参数。
  • 好吧,虽然我没有在繁重的计算中使用 lastLocation,但我确实缓存了“区域”(在繁重的部分中计算),以便在未更改时不发送通知,因为有些用户被他们打扰了,所以虽然你的回答确实帮助了我,但我仍然回到了我宁愿只在需要时才保存东西的地步(因为我的静态变量将被 android 的应用程序杀死)。但也许我只是太疯狂了,在没有必要的时候“不写SharedPreferences”,因为我怕我会“杀死”闪存,每次保存都可以......
  • 好吧,如果您知道每次位置更新都是一个新位置(即超出最小位移),则忽略警报超时。我认为您不会每分钟(移动时)或每次超时都将内容保存到 SharedPreference 中。
【解决方案2】:

我会建议一种不同的方法。为什么不使用警报管理器定期唤醒服务(理想情况下使用不准确的警报)以获取当前位置并检查它是否已发生足够的变化,然后在服务内部进行大量计算并将结果存储在数据库中或文件。

这样您就可以在更可控的环境中运行繁重的计算。

您还可以使用新的 JobScheduler (5+) 代替警报管理器。如果您需要兼容版本,有一个项目可以将 JobScheduler 带回 API 10+ (https://github.com/evant/JobSchedulerCompat)

【讨论】:

  • 一开始我在考虑使用不准确的警报(以节省电池),但我更喜欢使用融合定位服务,因为如果用户快速移动,我需要获取位置更新(让我们比如说在车里他可以移动 2 公里/分钟)在这种情况下进行繁重的计算很重要,因为他可能会在 1 分钟内移动到一个新的区域,但是我不想每分钟都唤醒电话,如果他在办公室里坐了 9 个小时。此外,即使我按照您的建议进行操作,我也会每次都保存 lastLocation,这或多或少是我现在所做的。
  • 您仍然可以使用融合位置提供程序,您可以从您的服务开始位置更新,然后在一段时间后停止它们。 CW 的 LocationPoller 使用了这种精确的方法:github.com/commonsguy/cwac-locpoll
猜你喜欢
  • 1970-01-01
  • 2017-11-02
  • 2022-11-25
  • 1970-01-01
  • 1970-01-01
  • 2016-04-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多