2

I am trying to start a service regularly every 30 second (even when the app is closed). but it runs one after another immediately. I started the service for the first time by:

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

and my service is

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();
        }
    }
}

why the service run by itself? how can I fix it to run just every 30s?

tshepang
  • 12,111
  • 21
  • 91
  • 136
user3021005
  • 41
  • 1
  • 5

3 Answers3

2

I am trying to start a service regularly every 30 second (even when the app is closed). but it runs one after another immediately.

This is i think very wrong approach. Service (its origin) is used for very long tasks and for processing some data. It's pretty designated for cases you want to have something that will run "forever".

Your described is normal behaviour - you can test it very simply - open running services in settings and then close your application in task manager and quickly look at your Service - will be stopped and immediately after started.

So i think your idea is not good designed. If you want to start some snippet of code every 30 seconds, better is to use for example Handler (only Handler or Handler in Service), good designated BroadcastReceivers - manipulating with sending right broadcasts and their handling etc.

Main purpose of Service is that runs in background until application will be unistalled and you should't try to change it (it's not very efficient).

One possible approach that came to my head (assume you want to do something every 30 seconds) is to use Handler and every 30 seconds send new broadcast that will make a trick.

Simon Dorociak
  • 33,374
  • 10
  • 68
  • 106
  • So why all tutorial learnt AlarmManager to run service regularly if it run constantly? is AlarmManager a wrong approach? – user3021005 Nov 24 '13 at 10:05
  • @user3021005 you don't understood what i said, i didnt say that alarmmanager is wrong i said that runs Service every 30 seconds doesnt make a sence and its wrong. – Simon Dorociak Nov 24 '13 at 10:10
1

create a broadcast receiver that will start your service after receiving broadcast from 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);
    }
}

start your broadcast receiver for the first time when you start your application:

    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);

Also add this to your Manifest File:

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

You should also have alook at this START_STICKY if you want your service to be started by Android system as soon as resources are available instead of receiving Broadcast by AlarmManager.

Answered a similar question here.

Community
  • 1
  • 1
Ankit Popli
  • 2,809
  • 3
  • 37
  • 61
0

The error in your code is putting cal.getTimeInMillis() in setRepeating.

AlarmManager's documentation says:

triggerAtMillis -> time in milliseconds that the alarm should first go off, using the appropriate clock (depending on the alarm type).

So you are forcing it to start "now".

MaciejGórski
  • 22,187
  • 7
  • 70
  • 94