android - 如何定期启动服务?

时间:2013-11-24 09:40:55

标签: android android-intent service alarmmanager

我试图每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秒运行一次?

3 个答案:

答案 0 :(得分:2)

  

我试图每30秒开始一次服务(即使是   该应用程序已关闭)。但它会立即一个接一个地运行。

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

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

所以我认为你的想法设计不好。如果你想每30秒启动一些代码片段,最好使用例如Handler(只有Handler或Handler in Service),好的指定BroadcastReceivers - 操纵发送正确的广播及其处理等

服务的主要目的是在后台运行,直到应用程序无法运行,您不应该尝试更改它(它不是非常有效)。

我想到的一种可能的方法(假设你想要每30秒做一次)是使用Handler并且每30秒发送一次新的广播就可以了。

答案 1 :(得分:1)

创建一个广播接收器,在接收到来自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

答案 2 :(得分:0)

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

AlarmManager's documentation说:

  

triggerAtMillis - &gt;使用适当的时钟(取决于报警类型),报警首先应该以毫秒为单位的时间。

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