【问题标题】:android - How start service regularly?android - 如何定期启动服务?
【发布时间】:2025-12-08 18:15:02
【问题描述】:

我正在尝试每隔 30 秒定期启动一项服务(即使应用程序已关闭)。但它立即一个接一个地运行。我通过以下方式首次启动该服务:

Intent i= new Intent(this, MyService.class);
this.startService(i);

我的服务是

public class MyService extends Service {

    public static String READ_NEMAD_URL = "http://...";

    @Override
    public void onStart(Intent intent, int startId) {
        ReadNemad task = new ReadNemad("GCAZ92");
        task.execute();
    }

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

    @Override
    public void onDestroy() {
        Calendar cal = Calendar.getInstance();

        Intent intent1 = new Intent(this, MyService.class);
        PendingIntent pintent = PendingIntent.getService(this, 0, intent1, 0);

        AlarmManager alarm = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
        // Start every 30 seconds
        alarm.setRepeating(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(),
                30 * 1000, pintent);
    }

    private class ReadNemad extends AsyncTask<String, Void, String> {

            //Do Somethings
            return response;
        }

        @Override
        public void onPostExecute(String response) {
            stopSelf();
        }
    }
}

为什么服务自己运行?我怎样才能让它每 30 秒运行一次?

【问题讨论】:

    标签: android android-intent service alarmmanager


    【解决方案1】:

    我正在尝试每隔 30 秒定期启动一项服务(即使 该应用程序已关闭)。但它会立即一个接一个地运行。

    这是我认为非常错误的做法。服务(它的起源)用于非常长的任务和处理一些数据。它非常适合您希望拥有“永远”运行的东西的情况。

    您描述的是正常行为-您可以非常简单地对其进行测试-在设置中打开正在运行的服务,然后在任务管理器中关闭您的应用程序并快速查看您的服务-将在启动后立即停止。

    所以我认为你的想法设计得不好。如果您想每 30 秒启动一些 sn-p 代码,最好使用例如 Handler(仅 Handler 或 Handler in Service),良好指定 BroadcastReceivers - 通过发送正确的广播及其处理等进行操作。

    Service 的主要目的是在后台运行,直到应用程序卸载,您不应该尝试更改它(效率不高)。

    我想到的一种可能的方法(假设您想每 30 秒执行一次)是使用 Handler 并且每 30 秒发送一次新的广播,这将成为一个技巧。

    【讨论】:

    • 那么为什么所有教程都学习了AlarmManager,如果它经常运行,它会定期运行服务? AlarmManager 是错误的方法吗?
    • @user3021005 你没听懂我说什么,我没说alarmmanager 错了我说每30 秒运行一次Service 并没有任何意义,而且是错的。
    【解决方案2】:

    创建一个广播接收器,它将在接收到来自AlarmManager 的广播后启动您的服务:

    public class SyncAlarm extends BroadcastReceiver {
    
    @Override
    public void onReceive(Context context, Intent data) {
    
        // set alarm to start service
        Calendar calendar = new GregorianCalendar();
        calendar.setTimeInMillis(System.currentTimeMillis());
    
        Calendar cal = new GregorianCalendar();
        cal.set(Calendar.DAY_OF_YEAR, calendar.get(Calendar.DAY_OF_YEAR));
        cal.set(Calendar.HOUR_OF_DAY,  calendar.get(Calendar.HOUR_OF_DAY));
    
        // start service after an hour
        cal.set(Calendar.MINUTE, calendar.get(Calendar.MINUTE) + 60);
        cal.set(Calendar.SECOND, calendar.get(Calendar.SECOND));
        cal.set(Calendar.MILLISECOND, calendar.get(Calendar.MILLISECOND));
        cal.set(Calendar.DATE, calendar.get(Calendar.DATE));
        cal.set(Calendar.MONTH, calendar.get(Calendar.MONTH));
    
        // set alarm to start service again after receiving broadcast
        AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
        Intent intent = new Intent(context, SyncAlarm.class);
        PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_ONE_SHOT);
        am.cancel(pendingIntent);
        am.set(AlarmManager.RTC, cal.getTimeInMillis(), pendingIntent);
    
        intent = new Intent(context, Reminder.class);
        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        context.startService(intent);
        }
    }
    

    在您启动应用程序时首次启动您的广播接收器:

        AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
        Intent intent = new Intent(context, SyncAlarm.class);
        PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_ONE_SHOT);
        am.cancel(pendingIntent);
        am.set(AlarmManager.RTC, System.currentTimeMillis(), pendingIntent);
    

    将此添加到您的清单文件中:

    <receiver android:name=".SyncAlarm" >
    </receiver>
    

    如果您希望 Android 系统在资源可用时立即启动您的服务,而不是通过 AlarmManager 接收广播,您还应该查看此 START_STICKY

    回答了类似的问题here

    【讨论】:

      【解决方案3】:

      您的代码中的错误是将cal.getTimeInMillis() 放入setRepeating

      AlarmManager's documentation 说:

      triggerAtMillis -> 闹钟应该首先响起的时间(以毫秒为单位),使用适当的时钟(取决于闹钟类型)。

      所以你强迫它“现在”开始。

      【讨论】: