【问题标题】:my Android service won't keep running我的 Android 服务无法继续运行
【发布时间】:2015-01-08 15:00:56
【问题描述】:

我有一个执行 AsyncTask 的服务,它在每次完成后调用自己。正如您将在下面看到的,我正在前台开始我的服务。当我将它插入我的计算机并将输出吐出到 LogCat 时,它成功启动并继续按预期运行。我知道这一点是因为为了测试,我的 AsyncTask 循环每 5 分钟吐出一个通知。但是,当我将其从计算机上拔下时,通知不会出现!好像服务在我启动后就完全停止了!

注意:我的服务是常规服务,而不是 IntentService。

这是我的 onStartCommand...

@SuppressWarnings("deprecation")
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    getData(intent);
    self = this;

    // Enter foreground state
    String title = "Service started.";
    String subject = "Service is running.";
    String body = "Monitoring...";
    Notification notification = new Notification(R.drawable.ic_launcher, title,
            System.currentTimeMillis());
    if(notificationSounds)
        notification.defaults |= Notification.DEFAULT_SOUND;
    else
        notification.sound = null;
    Intent notificationIntent = new Intent(this, MainActivity3.class);
    PendingIntent pendIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);
    notification.setLatestEventInfo(this, subject, body, pendIntent);
    startForeground(1500, notification);

    new BatteryLifeTask(appContext).execute();
    return START_NOT_STICKY;
}

这是我的异步任务:

// Looping AsyncTask for continuous mode
private class BatteryLifeTask extends AsyncTask<Void, Void, Void> {

    // Member variables
    Context appContext;
    int batteryPct0;

    public BatteryLifeTask(Context context) {
        super();
        appContext = context;
    }

    protected Void doInBackground(Void... params) {
        System.out.println("Entering doInBackground");
        // Get the initial battery level
        batteryPct0 = getBatteryPercent();
        System.out.println("Initial battery percent: " + batteryPct0);

        // Check time
        Calendar c = Calendar.getInstance();
        Date dateNow = c.getTime();
        // getTime returns ms, need minutes. 60000ms in a minute.
        long currTime = dateNow.getTime() / 60000;

        if(currTime >= timeToUse){
            finished = true;
            stopSelf();
        }

        System.out.println("Leaving doInBackground");
        return null;
    }

    @Override
    protected void onPostExecute(Void aVoid) {
        super.onPostExecute(aVoid);
        if(!finished) {
            int waitTime = 60000 * interval; // 1 minute is 60000 miliseconds
            System.out.println("Entering postExecute. waitTime is " + waitTime);
            Runnable r = new Runnable() {
                @Override
                public void run() {
                    if(!finished) { // In case postDelayed is pending, avoids extra notification
                        System.out.println("An interval has passed.");
                        calculateHelper(batteryPct0);
                        new BatteryLifeTask(appContext).execute();
                    }
                }
            };
            Handler h = new Handler();
            h.postDelayed(r, waitTime);
        }
    }
}

这是我创建通知的代码:

// Method for creating a notification
@SuppressWarnings("deprecation")
void notify0(int id, String title, String subject, String body, boolean playSound){
    NotificationManager NM = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
    Notification notify = new Notification(android.R.drawable.
    PendingIntent pending = PendingIntent.getActivity(
            getApplicationContext(), 0, new Intent(), 0);
    notify.setLatestEventInfo(getApplicationContext(), subject, body, pending);
    if(playSound)
        notify.defaults |= Notification.DEFAULT_SOUND;
    else
        notify.sound = null;

    // Cancel running notification if exists
    NM.cancel(id);

    // Push notification
    NM.notify(id, notify);
}



谁能帮我?这快把我逼疯了!插入并连接到 USB 调试时,我的应用程序可以完美运行。但是当拔掉电源时,服务似乎完全停止并且什么都不做。

【问题讨论】:

  • 不相关,但可以用// 1 minute is 60000 miliseconds代替developer.android.com/reference/android/text/format/…
  • @njzk2 谢谢,这很有帮助。使用警报管理器做什么?这有什么帮助?
  • @njzk2 是正确的:AlarmManager 是要走的路,而不是这种循环 AsyncTask:stackoverflow.com/a/14377875/603270
  • @shkschneider AsyncTask 是否进入睡眠状态/它可以被操作系统杀死吗?我需要它无限期地运行而不会中断。 AlarmManager 可以帮我做这个吗?

标签: java android android-intent android-asynctask android-service


【解决方案1】:

这是因为您在服务的onStartCommand() 上返回START_NOT_STICKY

START_NOT_STICKY 如果这样 服务的进程在启动时被杀死(从 onStartCommand(Intent, int, int)),并且没有新的开始意图 交付给它,然后将服务从启动状态中取出,然后 在未来明确调用之前不要重新创建 Context.startService(Intent)。

你应该返回START_STICKY

START_STICKY 如果该服务的进程在启动时被杀死(在从 onStartCommand(Intent, int, int) 返回之后),那么 将其保留在启动状态,但不要保留此传递的意图。 稍后系统会尝试重新创建服务。

检查此service api changes,尤其是服务生命周期更改部分。

【讨论】:

    【解决方案2】:

    返回 START_STICKY 而不是 START_NOT_STICKY 并查看您的设计。在您的情况下,最好使用具有 5 分钟超时时间的 AlarmManager,然后启动 IntentService。

    【讨论】:

    • 我的应用程序中的等待时间最长可以设置为 3 小时。设计的一部分是在 3 小时开始时获取电池电量,在 3 小时结束时获取电池电量,并找出差异以在该时间间隔内使用电池。它是预测算法的一部分。这 5 分钟的超时会对此产生干扰吗?
    • 随心所欲地设置警报管理器的超时时间,但使用警报管理器设置一个计时器并对其进行管理。这样可以避免任何电池消耗。
    • 您能否提供一个使用警报管理器完成的任务的示例?此外,它是否有前/后执行?我需要在 postExecute 中的代码之前执行和完成当前在 doInBackground 中的代码。我看到 AsyncTask 有这个功能,所以我选择在我的设计中使用它。
    • docs:developer.android.com/reference/android/app/AlarmManager.html 使用警报管理器,系统会向您的应用程序发送一个意图,您可以在超时到期时使用广播接收器捕获它,然后您可以启动一个意图服务。 IntentService 在后台运行,因此您无需担心任何事情。
    • 其他说明:您的设计是错误的,因为 CPU 可以在没有唤醒锁的情况下进入深度睡眠,但您真的不希望这样,否则您会耗尽用户电池,所以请使用警报管理器。
    猜你喜欢
    • 2021-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-11-18
    • 2015-09-18
    • 2015-02-14
    • 2013-01-11
    • 1970-01-01
    相关资源
    最近更新 更多