我可以在Application中使用什么类似于Activity.onPause()

时间:2015-01-06 20:38:14

标签: android caching sharedpreferences onpause

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

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

我注意到大部分时间,即使我不移动手机,我的代码也会一次又一次地调用繁重的计算。事实证明它是因为oldLocation为null(我的应用程序被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)[我这样做的原因是我使用了繁重计算的结果(通过调用此处未提供的其他函数) )从我的代码中的许多地方,我希望它尽可能地缓存]

2 个答案:

答案 0 :(得分:1)

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

通过这种方式,您可以为更繁重的计算运行提供更加可控的环境。

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

答案 1 :(得分:1)

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

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

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