7

I have an infinite loop in my IntentService to update my view once every 30 seconds based on the input from the main activity.

public class IntentServiceTest extends IntentService {

String Tag = "IntentServiceTest";
String ACTION_RCV_MESSAGE = "com.jsouptest8.intent.action.MESSAGE";

public IntentServiceTest(){
    super("IntentServiceTest");
    Log.d(Tag, "IntentServiceTest constructor");
}

@Override
protected void onHandleIntent(Intent intent) {
    // TODO Auto-generated method stub
    Log.d(Tag, "in onHandleIntent");
    String url = intent.getStringExtra("URL");
    Document doc;
    int i=0;
    try{
      while(true){
         Log.d(Tag, "entered try block...");
         Log.d(Tag, "url = "+url);
         doc = Jsoup.connect(url)
         .get();

       Log.d(Tag, "past Jsoup.connect");
         Element data = doc.select("table").get(1).attr("bgcolor", "#f4f36f");
         Log.d(Tag, data.toString());
         Log.d(Tag, data.text());
         Log.d(Tag, "creating intent...");
         Intent broadcastIntent = new Intent();
         Log.d(Tag, "setting action...");
         broadcastIntent.setAction(ACTION_RCV_MESSAGE);
         broadcastIntent.addCategory(Intent.CATEGORY_DEFAULT);
         broadcastIntent.putExtra("OUTPUT", data.toString());
         Log.d(Tag, "sending broadcast: "+(i++));
         sendBroadcast(broadcastIntent);
         Thread.sleep(30*1000);
      }
    }
    catch(StackOverflowError e){
        Log.d(Tag, "in StackOverflowError block...");
        Log.d(Tag, "creating intent...");
        Intent broadcastIntent = new Intent();
        Log.d(Tag, "setting action...");
        broadcastIntent.setAction(ACTION_RCV_MESSAGE);
        broadcastIntent.addCategory(Intent.CATEGORY_DEFAULT);
        broadcastIntent.putExtra("OUTPUT", "系統忙線中, 請稍後再試");
        Log.d(Tag, "sending broadcast...");
        sendBroadcast(broadcastIntent);
    }
    catch(Exception e){
        Log.d(Tag, "in catch Exception block...");   
        onHandleIntent(intent);
    }
}

}

The problem is, I am stuck in this loop. Even if I kill the main activity and then return to it to enter a new input and the IntentService still returns based on the old input.

I need to know how I can update myself from the URL every 30 second without getting stuck. Thanks!

Jason Ching
  • 1,037
  • 4
  • 19
  • 27

4 Answers4

7

An IntentService is meant to finish of a task and return. It does this task in a new thread. Do not use while loop in IntentService. Your IntentService will get killed after sometime. I am telling this from personal experience. I tried using a while loop in it. And at the end of the while loop I used sleep(60000) i.e 1 minute. But I found that my IntentService was killed after sometime.

I would recommend you not to use an AlarmManager for 30 seconds, as some have siggested. Because 30 seconds is too short. it will drain the battery. For AlarmManager use a minimum 1 minute with RTC.

If you still want it to be 30 seconds, use a service. In the service use your logic. But do that in a separate thread i.e spawn a new thread in your Service and used while loop there and sleep(). And do not forget to use startForeGround. This reduces the probabilty of android killing your service greatly.

Ashwin
  • 12,691
  • 31
  • 118
  • 190
  • do you have the tutorial for alarmmanager to execute the intentservice in every 30 seconds? @Ashwin or maybe what is your solution if i want to make the service run for every 12 seconds then? – gumuruh Jul 13 '14 at 06:27
  • If you should choose between an AlarmManager every minute and a Service with its own loopen thread... what would you choose? – andrea.rinaldi Jun 15 '15 at 11:10
2

Using a while statement inside an IntentService, or any kind of Service for that matter is a bad idea. It is especially a bad idea inside an IntentService because the IntentService is supposed to finish a task and then get terminated automatically, you are in essence defeating the whole purpose of using an IntentService.

I would recommend to remove the loop in the IntentService and to use an alarm to wake up the IntentService every 30 seconds. That way, your service gets called every 30 seconds for sure and for the time that it is not processing, it can actually go back to sleep. Moreover, to handle cases where a new call to the IntentService is received while the IntentService is servicing an older request, you can add code to the onStartCommand method of your IntentService to see if the call should be enqueued for processing or ignored altogether.

Set an alarm using this method:

public void setRepeating (int type, long triggerAtMillis, long intervalMillis, PendingIntent operation)

Link: http://goo.gl/E9e6

For a more efficient approach, use setInexactRepeating (but that does not guarantee a 30 second wakeup)

PS. We don't normally override the onStartCommand of an IntentService but it can be done if your app really that functionality.

Soham
  • 4,940
  • 3
  • 31
  • 48
1

in this link you'll find a service that updates itself using a timer

Keep Service running

If your comfortable with the while loop just write an if statement that exists the loop

if(thisIsTrue)
 {
   break; // this will exit the loop!
 }
Community
  • 1
  • 1
Hossam Alaa
  • 663
  • 5
  • 9
  • How do I send thisIsTrue back from the main activity to the IntentService? The IntentService seemed just stuck within the loop and not taking any more new inputs anymore. I don't want a service the keeps on running. I would like it to stop when I enter a new input for query or when I kill the activity by the back button for example. – Jason Ching Aug 18 '12 at 07:32
0

It would be better that you keep the loop or timer or any such running task in the MainActivity itself and execute IntentService everytime. Because IntentService will perform task and finish itself everytime or queue the task to be delivered further.

From the Docs -

IntentService will receive the Intents, launch a worker thread, and stop the service as appropriate.

It uses work queue processor pattern to maintain the task.

Lalit Poptani
  • 67,150
  • 23
  • 161
  • 242