安卓闹钟管理器在几个小时后停止

4

我创建了一个闹钟管理器,每5秒启动一次服务,应用程序运行良好,但几个小时后闹钟管理器停止运行。请注意,该应用程序未被用户使用,这意味着它在后台运行而没有用户交互。有没有人知道如何每隔几秒启动一次服务而不停止?

AlarmManager am = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(context, AlarmManagerBroadcastReceiver.class);
intent.putExtra(ONE_TIME, Boolean.TRUE); 
PendingIntent pi = PendingIntent.getBroadcast(context, 0, intent, 0);
am.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + (1000 * 60 * 5), pi); 

1
把你的代码放在这里。 - piotrpo
1个回答

1

不要使用闹钟管理器做这样的事情。闹钟管理器更多是一个概念,用于执行在几小时内完成的任务(在最佳情况下)。

如果您需要对任务进行精确处理,请在服务中使用处理程序,并使用它来后置执行您的可运行文件。 在您的可运行文件内,调用方法以再次后置执行可运行文件。

将可运行文件和处理程序保存为服务的成员变量,并使该过程保持黏性。如果您想停止服务和处理程序(如果您只调用stopService(Context)或Service.stopSelf(),则处理程序不会停止),则需要使用处理程序上的removeCallbacks(runnable)来调用您的可运行文件。

干杯。

Btw:请考虑是否真的想每5秒启动一次服务。 也许只需在我刚才描述的服务的可运行文件内完成服务工作。

Edit2:如果您需要服务可靠,请添加一个广播接收器来处理启动操作,在启动时接收广播并重新启动您的服务。

Edit3:检查您的服务是否正在运行的代码,而无需启动它:

    public static boolean isRunning(Context context) {
    ActivityManager manager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
    for (ActivityManager.RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
        if (YourService.class.getName().equals(service.service.getClassName())){
            return true;
        }
    }
    return false;
}

但是,在onStartCommand中检查您的成员变量'handler'是否为null,并忽略请求启动,因为这可能会导致多个可运行处理程序的情况。

Edit4:

服务代码片段:

public class LoopingServiceSnipped extends Service{

public static final long STANDARD_FREQUENCY = 1000;
private static       long         loopingFrequency         = STANDARD_FREQUENCY;
private Handler  serviceHandler; 
private Runnable loop; 

//EXTRAS

private static final String       INTENT_EXTRA_STOP_SERVICE  = LoopingServiceSnipped.class.getSimpleName() + "_INTENT_EXTRA_STOP_SERVICE";
private static final String       INTENT_EXTRA_FREQUENCY     = LoopingServiceSnipped.class.getSimpleName() + "_INTENT_EXTRA_FREQUENCY";

/**
 * Determines if the service is running (reliably) without starting it.
 *
 * @param context
 *         needed for SystemServices
 *
 * @return true if the service is running
 */
public static boolean isRunning(Context context) {
    ActivityManager manager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
    for (ActivityManager.RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
        if (LoadingScreenAppDetectionService.class.getName().equals(service.service.getClassName())){
            return true;
        }
    }
    return false;
}

public static void stopService(Context c) {
    Intent i = new Intent(c, LoopingServiceSnipped 
    i.putExtra(INTENT_EXTRA_STOP_SERVICE, true);
    c.startService(i);
 }

public static synchronized void setFrequency(Context c, long frequency) {
    Intent i = new Intent(c, LoadingScreenAppDetectionService.class);
    i.putExtra(INTENT_EXTRA_FREQUENCY, frequency);
    c.startService(i);
}

@Override
public void onCreate() {
    super.onCreate();
    init();
}

private void init() {
    //do your initialization here
}

@Nullable
@Override
public IBinder onBind(Intent intent) {
    return null;
}

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    if (shouldStopService(intent)){
        LOG.d("Going to stop service!");
        tryStopService();
        return Service.START_NOT_STICKY;
    } else {
        return startOrContinueService(intent);
    }
}

private void tryStopService() {
    stopLooping();
    stopSelf();
}

private void stopLooping() {
    if (serviceHandler != null){
        serviceHandler.removeCallbacks(getLoop());
        serviceHandler = null;
    }
}

private int startOrContinueService(Intent intent) {
    if (hasNewFrequency(intent)){
        setFrequency(intent);
        stopLooping();
    }
    if (!isServiceRunning()){
     startLooping();
        }
    } else {
        LOG.d("Going to continue with service!");
    }
    return Service.START_STICKY;
}


private boolean hasNewFrequency(Intent intent) {
    return intent.hasExtra(INTENT_EXTRA_FREQUENCY);
}

private void setFrequency(Intent intent) {
    if (intent.hasExtra(INTENT_EXTRA_FREQUENCY)){
        loopingFrequency = intent.getLongExtra(INTENT_EXTRA_FREQUENCY, STANDARD_FREQUENCY);
    }
}

private boolean isServiceRunning() {
    return serviceHandler != null;
}

private boolean shouldStopService(Intent i) {
    if (i.hasExtra(INTENT_EXTRA_STOP_SERVICE)){
        return i.getBooleanExtra(INTENT_EXTRA_STOP_SERVICE, false);
    } else {
        return false;
    }
}

private void startLooping() {
    if (serviceHandler == null){
        serviceHandler = new Handler();
    }
    serviceHandler.postDelayed(getAppDetectionLoop(), getFrequency());
}

private Runnable getLoop() {
    if (loop == null){
        loop = new Runnable() {
            @Override
            public void run() {
                //do your looping work here
                startLooping();
            }
        };
    }
    return loop;
}

此外,还需要添加引导接收器和屏幕开启接收器。

1
这就是为什么要将Service设置为sticky的原因(在"OnStartCommand"方法中返回sticks)。一个sticky service会在它死亡后再次启动。为了绝对保险起见,添加一个开机接收器和一个屏幕打开的接收器,并检查你的service是否仍在运行。 - JacksOnF1re
偶尔会被杀掉。毫无疑问。但它很快就会重新启动。 - JacksOnF1re
1
非常感谢你,Jack。我会亲自测试并计算服务停止的确切时间以及何时再次运行,并在此发布,也许对某些人有帮助 :) 你能放上你自己的代码吗? - Amalo
1
没问题 :) 如果你需要的话,我可以添加更多的代码,但可能要等到周末。待会儿见。 - JacksOnF1re
1
抱歉回复晚了,周末也得工作。今天会添加的。 - JacksOnF1re
显示剩余8条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接