Wakka02
Wakka02

Reputation: 1541

stopService() not working

I have an IntentService that does the following:

protected void onHandleIntent(Intent intent) {
    // TODO Auto-generated method stub
    while (true) {
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        System.out.println("Hello, World!");
    }
}

The above is a sample of the code I am using. I intend to replace the println() with a HTTP Request sent to a server, but for now I am using this as a test. I call startService() as such:

@Override
public void onPause() {
    ConnectionUtility.getInstance().startService(this);
    super.onPause();
}

@Override
public void onDestroy() {
    ConnectionUtility.getInstance().startService(this);
    super.onDestroy();
}

@Override
public void onStop() {
    ConnectionUtility.getInstance().startService(this);
    super.onStop();
}

where my custom startService method does this:

public void startService(Activity activity) {
    if (!isMyServiceRunning(activity)) {
        Intent intent = new Intent(activity, BackgroundUpdateService.class);
        activity.startService(intent);
    }
}

Note: the isMyServiceRunning() method is a custom method I found elsewhere to determine if the Service is running. The method works as far as I know.

Now, the purpose of this Service is to trigger the println() whenever the particular Activity exits (either via onPause(), onDestroy() or onStop()), and when onCreate() or onResume() runs, the Service is to be stopped like so:

@Override
public void onResume() {
    ConnectionUtility.getInstance().stopServiceIfRunning(this);
    super.onResume();
}

Going one step deeper into stopServiceIfRunning():

public void stopServiceIfRunning(Activity activity) {
    if (isMyServiceRunning(activity)) {
        Intent intent = new Intent(activity, BackgroundUpdateService.class);
        activity.stopService(intent);
    }
}

Now here's the problem: I can start the Service alright, when I back out of the Activity via the Home/Back button or when I switch to a different Activity, the startService() method kicks in and it runs perfectly; that is to say, "Hello, World!" is printed every 5seconds as needed. But when I navigate back to the Activity, I can determine that my custom stopServiceIfRunning() method runs and the code enters the IF block fine (confirmed), but the service doesn't stop and the "Hello, World!"s just keep coming. What am I doing wrong?

---EDIT--- In response to Seraphim's comment:

private boolean isMyServiceRunning(Activity activity) {
    ActivityManager manager = (ActivityManager) activity.getSystemService(Context.ACTIVITY_SERVICE);
    for (RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
        if (BackgroundUpdateService.class.getName().equals(service.service.getClassName())) {
            return true;
        }
    }
    return false;
}

But again, this method is returning true and false values accurately thus far, so I don't think this is the problem.

Upvotes: 0

Views: 8589

Answers (2)

Wakka02
Wakka02

Reputation: 1541

Finally figured out a way to do it, really really thankful to Seraphim for helping me out so much though.

I ended up overriding the onDestroy() method of my custom IntentService class. This is what I came up with:

public class BackgroundUpdateService extends IntentService {

    private boolean status;

    public BackgroundUpdateService() {
        super("BackgroundUpdateService");
        // TODO Auto-generated constructor stub
    }   

    @Override
    protected void onHandleIntent(Intent intent) {
        status = true;
        // TODO Auto-generated method stub
        while (status) {
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            System.out.println("Hello, World!");
        }
    }

    @Override
    public void onDestroy() {
        status = false;
        super.onDestroy();
    }
}

Evidently, the onDestroy() method is called whenever .stopService(intent) is called, so I made use of this fact to stop the while loop while I'm at it. This circumvents the reliability issue because each Service gets its own boolean variable and is not dependent on a static variable, and doesn't require any additional variables to be passed through the Intent.

Again, thanks to Seraphim for taking the time to help me out so much.

Upvotes: 2

Seraphim's
Seraphim's

Reputation: 12768

Stopping services is not a synchronous operation. If your check for service termination is close to the previous "service stop" call, you may find your service is still running.

In my app when I need to stop services (when exiting app) I enter in a loop cycle (using AsyncTask) and wait for service termination.

I see you call

@Override
public void onDestroy() {
    ConnectionUtility.getInstance().startService(this);
    super.onDestroy();
}

I suggest to use Application Context for starting and stopping your service and not the Activity as a context. Because you're starting your service when the activity is going to be destroyed!

Also the part

protected void onHandleIntent(Intent intent) {
    // TODO Auto-generated method stub
    while (true) {
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        System.out.println("Hello, World!");
    }
}

A infinite loop when handling an intent? Sounds not very good to me.

Upvotes: 0

Related Questions