0

在工作中,我们创建了一个应用程序,该应用程序将跟踪用户上下班的路线,并且我们内置了自动记录功能,但它的行为方式并不像我们想要的那样。在不活动一两天后,操作系统似乎关闭了这个自动系统(手机在此期间甚至没有移动,它们基本上仅用于测试)。

在 iOS 上,我们使用 CLRegions 在用户当前位置周围创建几个区域,在用户的确切位置创建了 5 个具有不同半径的区域,并在用户周围 10 米的距离处创建了 12 个区域(这些半径为 80 米)。还指示 CLLocationManager 对象开始监视重大更改和访问(尽管它们甚至还没有被触发一次)。

在 Android 上,我们通过 LocationServices API 使用地理围栏,这里我们只有用户当前位置周围的 5 个增量半径。如果用户在 Android 上关闭应用程序或重新启动手机,它将启动后台服务,该服务将重新初始化地理围栏并开始监控它们。

当我通过在外面走一点来测试它们时,这两个系统都工作得很好,但似乎在一两天不活动(也就是周末)之后它们停止工作。我已经调试了很长时间了,尽管它变得更好了,但它仍然不完美。

无论应用程序关闭多长时间,当地理围栏/区域被触发时,是否有一个可靠的系统在后台自动启动应用程序?我知道这两个操作系统处理后台任务的方式非常不同,但我不太确定这种方式对 GPS 使用的长期限制。

我们正在制作的应用程序是用 Xamarin Forms 编写的,但这些系统是在其本机项目中编写的(仍然使用 C#,但可以完全访问整个本机平台)

4

1 回答 1

0

Android服务的问题是操作系统会杀死后台服务,因为它被认为是低优先级,然后以定时间隔重新启动。这可能会在几天内发生多次,每次都会增加重新启动服务之前的时间长度(有些手机只是使用设定的时间,没有增加)。

我的建议是,如果你想要一个永远在线的服务,你需要把它变成一个前台服务。我会给出一些代码示例来说明如何实现这一点,但我不太了解 Xamarin,所以我不想给你任何不好的例子。

另一种方法是使用带有PendingIntent的AlarmManager来检查服务是否正在运行并在未运行时启动它。请注意,如果您经常这样做,可能会导致明显的电池消耗,但如果您不经常这样做,您可能会错过地理围栏事件。

希望这会有所帮助,祝你好运!

更新#1

以下是在前台运行服务和运行 AlarmManager 的代码示例。

前景

这确实是让您的应用程序保持活力的最简单方法。

public class ForegroundService extends Service{
    @Override
    public int onStartCommand(Intent intent, int flags, int startId){
        Notification notification = new NotificationCompat.Builder(this)
                .setSmallIcon(R.mipmap.icon)
                .setContentTitle("TITLE")
                .setContentText("This is an example notification!")
                .build();
        startForeground(ID, notification);
        //Do your stuff here
    }

    @Override
    public void onDestroy(){
        super.onDestroy();
        stopForeground(true);
        //If you have anything else you want done here...
    }
}

报警管理器

这将按照您设置的时间间隔(本示例为 10 分钟)不断尝试创建此服务。不过,这里有一些陷阱。首先,由于 Android 6.0 引入了 Doze Mode,AlarmManager 可能不会在手机处于睡眠状态时触发,这意味着该服务可能会死掉一段时间。其次,这是onStartCommand多次调用该函数,因此您需要逻辑来处理它。

public class AlwaysOnService extends Service{
    @Override
    public int onStartCommand(Intent intent, int flags, int startId){

        AlarmManager am = (AlarmManager)getSystemService(ALARM_SERVICE);
        PendingIntent pi = PendingIntent.getService(this, requestCode, new Intent(this, AlwaysOnService.class), PendingIntent.FLAG_UPDATE_CURRENT);
        am.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime() + MIN_10_IN_MILLIS, pi);
        //Do your stuff here
        return START_STICKY;
    }

    @Override
    public void onDestroy(){
        super.onDestroy();
        AlarmManager am = (AlarmManager)getSystemService(ALARM_SERVICE);
        PendingIntent pi = PendingIntent.getService(this, requestCode, new Intent(this, AlwaysOnService.class), PendingIntent.FLAG_NO_CREATE);
        if(pi != null){
            am.cancel(pi);
            pi.cancel();
        }
        //If you have anything else you want done here...
    }
}

在这两者中,将服务设置为前台服务可能是最简单的事情,除非你真的不能拥有,否则 AlarmManager 是采取的路线。

于 2016-07-25T17:10:29.620 回答