-1

I have a Handler that is inside a Service and I block this thread until the user chooses to stop the service. To make it less CPU intensive I am trying to use Thread.sleep() and repeat checking the blocking condition after an interval of 10 minutes. Here's my implementation of my handlemessage :

@Override
public void handleMessage(Message msg) {
    Log.e("Service", "looper started");
    GPSThread gp=new GPSThread(getApplicationContext());
    gp.start();         
    ModeController mc=new ModeController(getApplicationContext());
    mc.start();
    NetworkSniffer nh=new NetworkSniffer(getApplicationContext());
    nh.start();
    while(stopService)    //stopService is a volatile boolean i use to block until user opts to stop the service
    {                   
        try {
            Thread.sleep(10*60*1000);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
                e.printStackTrace();
        }               
    }    
    mc.stopThread();
    gp.stopThread();
    nh.stopNetworkThread();
    stopSelf(msg.arg1);
}

Now my problem is that if I change the value of stopService to false (through a public function) it might take upto 10 minutes to quit the while loop. If it were a thread I would have used a Thread.interrupt() and quit the while loop.

So my question is how do I achieve a similar thing for Handler i.e, how to throw a InterruptedException for Thread.sleep() inside a Handler.

Sourav Kanta
  • 2,727
  • 1
  • 18
  • 29

2 Answers2

1

If it were a thread I would have used a Thread.interrupt() and quit the while loop.

Actually, the code >>is<< running on a thread, so you if you could work out what that thread is, you could interrupt it.

Putting that aside, the way that you should do this is to have the code where you would have tried to interrupt the thread call Service.stopService.

References:

This approach works when the thread that is sleeping is the service's handler thread. If you have explicitly created the thread yourself, then you will need to keep track of the thread our created and use Thread.interrupt on it. (And you could use the Thread.interrupted state rather than a custom stopService flag.)

However, a better idea would be to avoid the sleep loop: https://stackoverflow.com/a/845291/139985

Community
  • 1
  • 1
Stephen C
  • 698,415
  • 94
  • 811
  • 1,216
  • Thank you very much for the links sir, I am going through them. I just didn't get one thing though. You said that if I could work out the thread I could call an interrupt on it. How can i work out the thread Sir? – Sourav Kanta May 26 '16 at 23:17
  • It would probably be difficult. (In the classic Java world, you would probably use the ThreadGroup hierarchy and find the thread by name. But that's a bad idea.) If you can't use serviceStop, then the best idea is to record the thread reference in a variable somewhere ... – Stephen C May 27 '16 at 01:29
  • Thank you Sir, finally got it to work. I got the Thread instance from the HandlerThread object that I use `HandlerThread thread = new HandlerThread("ServiceStartArguments",Process.THREAD_PRIORITY_BACKGROUND);`. Finally I called an interrupt on this thread variable in `stopServiceMethod()`. – Sourav Kanta May 28 '16 at 08:55
1

Thanks to @Stephen C finally got it to work. Posting my code in the hope that it might help others in the future :

package com.example.userpc.roadtracker;


import android.app.Service;
import android.content.Intent;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
import android.os.Process;
import android.util.Log;

/**
 * Created by USER PC on 5/21/2016.
 */
public class MainServiceThread extends Service {

    private Looper mServiceLooper;
    private ServiceHandler mServiceHandler;
    private volatile static boolean stopService=true;
    private static HandlerThread mThread;

    public static void stopServiceThread()
    {
        stopService=false;
        mThread.interrupt();
    }

    private final class ServiceHandler extends Handler {
        public ServiceHandler(Looper looper) {
            super(looper);
        }
        @Override
        public void handleMessage(Message msg) {
            Log.e("Service", "looper started");
            GPSThread gp=new GPSThread(getApplicationContext());
            gp.start();         
            ModeController mc=new ModeController(getApplicationContext());
            mc.start();
            NetworkSniffer nh=new NetworkSniffer(getApplicationContext());
            nh.start();
            while(stopService)
            {                   
                try {
                    Thread.sleep(10*60*1000);

                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }               
            }    
            mc.stopThread();
            gp.stopThread();
            nh.stopNetworkThread();
            stopSelf(msg.arg1);
        }
    }

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

    @Override
    public void onCreate() {
        Log.e("Service", "in onCreate");
        stopService=true;
        HandlerThread thread = new HandlerThread("ServiceStartArguments",
                Process.THREAD_PRIORITY_BACKGROUND);
        mThread=thread;
        thread.start();
        mServiceLooper = thread.getLooper();
        mServiceHandler = new ServiceHandler(mServiceLooper);
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.e("Service","Started");
        Message msg = mServiceHandler.obtainMessage();
        msg.arg1 = startId;
        mServiceHandler.sendMessage(msg);
        return START_STICKY;
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        mThread=null;
        Log.e("Service","Destroyed");
    }


}
Sourav Kanta
  • 2,727
  • 1
  • 18
  • 29