Marie
Marie

Reputation: 721

Stopping Service results in orphaned thread

I am continuing to study from the book "Pro Android 2," working through the Service example that consists of two classes: BackgroundService.java and MainActivity.java. The MainActivity class is shown below and has a couple buttons. The unbind button, unbindBtn, stops the Service but doesn't appear to do much else like kill the thread the Service started.

    public class MainActivity extends Activity {
        private static final String TAG = "MainActivity";

        @Override
        public void onCreate(Bundle savedInstanceState)
        {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.main);

            Log.d(TAG, "starting service");

            Button bindBtn = (Button)findViewById(R.id.bindBtn);
            bindBtn.setOnClickListener(new OnClickListener() {

                @Override
                public void onClick(View arg0) {
                    Intent backgroundService = new Intent(MainActivity.this, com.marie.mainactivity.BackgroundService.class);
                    startService(backgroundService);
                }
            });

            Button unbindBtn = (Button)findViewById(R.id.unbindBtn);
            unbindBtn.setOnClickListener(new OnClickListener() {
                @Override
                public void onClick(View arg0) {
                    stopService(new Intent(MainActivity.this, BackgroundService.class));
                }
            });
        }
    }

The documentation says "if your service is going to do any CPU intensive work or blocking operations..., you should create a new thread within the service to do that work." And that's exactly what the BackgroundService class does below. As you can see below I've added a while(true) loop in the thread's run() method to see what happens to the thread when I stop the Service.

    public class BackgroundService extends Service {
        private NotificationManager notificationMgr;

        @Override
        public void onCreate() {
            super.onCreate();

            notificationMgr = NotificationManager)getSystemService(NOTIFICATION_SERVICE);

            displayNotificationMessage("starting Background Service");

            Thread thr = new Thread(null, new ServiceWorker(), "BackgroundService");
            thr.start();
        }   

        class ServiceWorker implements Runnable
        {
            public void run() {
                // do background processing here...

                long count = 0;
                while (true) {
                    if (count++ > 1000000)
                    {
                        count = 0;
                        Log.d("ServiceWorker", "count reached");
                    }
                }

                //stop the service when done...
                //BackgroundService.this.stopSelf();
            }
        }

        @Override
        public void onDestroy()
        {
            displayNotificationMessage("stopping Background Service");
            super.onDestroy();
        }

        @Override
        public void onStart(Intent intent, int startId) {
            super.onStart(intent, startId);
        }

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

        private void displayNotificationMessage(String message)
        {
            Notification notification = new Notification(R.drawable.note, message, System.currentTimeMillis());

            PendingIntent contentIntent = PendingIntent.getActivity(this, 0, new Intent(this, MainActivity.class), 0);

            notification.setLatestEventInfo(this, "Background Service", message, contentIntent);

            notificationMgr.notify(R.id.app_notification_id, notification);
        }
    }

When I press the unbind button, unbindBtn, in the MainActivity class I trust the Service in this example will be stopped. But from what I can see in logcat the thread that was started by the Service continues to run. It's like the thread is now some kind of orphan with no apparent way to stop it. I've seen other source code use a while(true) loop in a thread's run() method. This seems bad unless a way to break out of the loop is provided. Is that typically how it's done? Or are there other ways to kill a thread after the Service that started it has stopped?

Upvotes: 1

Views: 2559

Answers (1)

nicholas.hauschild
nicholas.hauschild

Reputation: 42849

You should provide a 'running' boolean.

while(running) {
    //do your stuff
}

You want to make it something that you can update. Perhaps your Service's onDestroy() method should call a stopProcessing() method on your Runnable, which will set the 'running' boolean to false.

Upvotes: 4

Related Questions