Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Location listener works from a Service but not an IntentService

I have an app where I am trying to periodically get user location and send to server. I have a service attached to an AlarmManager which executes every minute (for testing). The service finds the user location correctly and logs out the GPS co-ords. Once there is a GPS lock I cancel the location request and stop the service. When I ask for location updates, I start a Handler that executes 20 seconds later, this Handler removes the location update and stops the Service in case no lock is achieved. All this works.

Below is the code that works using the Service class.

public class TrackingService extends Service {

    private static final String TAG = TrackingService.class.getSimpleName();
    LocationManager             mlocManager;
    LocationListener            mlocListener;
    NfcScannerApplication       nfcscannerapplication;
    String carerID;

    Handler endServiceHandler;
    Runnable endServiceRunnable;

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

        nfcscannerapplication = (NfcScannerApplication) getApplication();
        mlocManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
        mlocListener = new MyLocationListener();

        Log.e(TAG, "Service created and location manager and listener created");

    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.e(TAG, "in onDestroy in LocationService class");
        mlocManager.removeUpdates(mlocListener);


    }

    @Override
    public void onStart(Intent intent, int startId) {
        super.onStart(intent, startId);
        mlocManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, mlocListener);
        Log.e(TAG, "requesting location updates");

        enableMenuButtonsHandler();
        endServiceHandler.postDelayed(endServiceRunnable,20 * 1000);
    }

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

    private class MyLocationListener implements LocationListener {

        @Override
        public void onLocationChanged(Location loc) {


            Log.e(TAG, "in TrackingService onlocationChanged and about to send lon/lat " + loc.getLongitude() + " " + loc.getLatitude());


            DateTime dt = new DateTime();
            DateTimeFormatter df3 = DateTimeFormat.forPattern("yyyy-MM-dd H:mm:ss.SSS");
            String formattedNowTime3 = df3.print(dt);
            Log.e(TAG, "Time of location fix in TrackingServive = " + formattedNowTime3);


            Cursor c = nfcscannerapplication.loginValidate.queryAllFromCarer();

            if (c.getCount() > 0) {
                if(c.moveToLast()){

                carerID = c.getString(c.getColumnIndex(LoginValidate.C_CARER_ID));

                }
            }

             Log.e(TAG, "carer ID = " + carerID);

             mlocManager.removeUpdates(mlocListener);
             Log.e(TAG, "removed updates(TrackingService)");

             TrackingService.this.stopSelf();
             Log.e(TAG, "called stopSelf on TrackingService");

        }

        @Override
        public void onProviderDisabled(String provider) {
            // TODO Auto-generated method stub

        }

        @Override
        public void onProviderEnabled(String provider) {
            // TODO Auto-generated method stub

        }

        @Override
        public void onStatusChanged(String provider, int status, Bundle extras) {
            // TODO Auto-generated method stub

        }

    }// end of MyLocationListener


    public void enableMenuButtonsHandler() {

        endServiceHandler = new Handler();
        endServiceRunnable = new Runnable() {
            public void run() {

                endService();

            }

            private void endService() {

                 mlocManager.removeUpdates(mlocListener);
                 Log.e(TAG, "removed updates(TrackingService) from the endService handler");

                 TrackingService.this.stopSelf();
                 Log.e(TAG, "called stopSelf on TrackingService from the endService handler");

            }
        };

    }


}// end of service 

The problem I am having is once I have a GPS lock, I want to send the long and lat co-ords to the server. I know I can use AsyncTask from a Service but I don't want to do this. I would prefer to use IntentService as it runs in its own background thread. This way I can make network call directly from the IntentService.

The following code implements the IntentService class but it doesn't seem to get a lock. The GPS keeps flashing on the phone indefinitely. The logging statements get as far as 'requesting location updates', then nothing after that.

Has anyone any ideas why no lock is achieved? Thanks in advance.

public class TrackingService extends IntentService {

   private static final String TAG = TrackingService.class.getSimpleName();
   LocationManager             mlocManager;
   LocationListener            mlocListener;
   NfcScannerApplication       nfcscannerapplication;
   String carerID;

   Handler endServiceHandler;
   Runnable endServiceRunnable;

    public TrackingService() {
        super("TrackingService");

    }

    @Override
    protected void onHandleIntent(Intent intent) {

           nfcscannerapplication = (NfcScannerApplication) getApplication();
           mlocManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
           mlocListener = new MyLocationListener();
           Log.e(TAG, "Service created and location manager and listener created");

           mlocManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, mlocListener);
           Log.e(TAG, "requesting location updates");

           enableMenuButtonsHandler();
           endServiceHandler.postDelayed(endServiceRunnable,20 * 1000);

    }



     private class MyLocationListener implements LocationListener {

                 @Override
                 public void onLocationChanged(Location loc) {


                    Log.e(TAG, "in TrackingService onlocationChanged and about to send lon/lat " + loc.getLongitude() + " " + loc.getLatitude());


                     DateTime dt = new DateTime();
                     DateTimeFormatter df3 = DateTimeFormat.forPattern("yyyy-MM-dd H:mm:ss.SSS");
                     String formattedNowTime3 = df3.print(dt);
                     Log.e(TAG, "Time of location fix in TrackingServive = " + formattedNowTime3);


                     Cursor c = nfcscannerapplication.loginValidate.queryAllFromCarer();

                    if (c.getCount() > 0) {
                        if(c.moveToLast()){

                        carerID = c.getString(c.getColumnIndex(LoginValidate.C_CARER_ID));

                        }
                    }

                     Log.e(TAG, "carer ID = " + carerID);

                     mlocManager.removeUpdates(mlocListener);
                     Log.e(TAG, "removed updates(TrackingService)");

                     TrackingService.this.stopSelf();
                     Log.e(TAG, "called stopSelf on TrackingService");

                 }

                 @Override
                 public void onProviderDisabled(String provider) {
                     // TODO Auto-generated method stub

                 }

                 @Override
                 public void onProviderEnabled(String provider) {
                     // TODO Auto-generated method stub

                 }

                 @Override
                 public void onStatusChanged(String provider, int status, Bundle extras) {
                     // TODO Auto-generated method stub

                 }

             }// end of MyLocationListener


     public void enableMenuButtonsHandler() {

                endServiceHandler = new Handler();
                endServiceRunnable = new Runnable() {
                    public void run() {

                        endService();

                    }

                    private void endService() {

                         mlocManager.removeUpdates(mlocListener);
                         Log.e(TAG, "removed updates(TrackingService) from the endService handler");

                         TrackingService.this.stopSelf();
                         Log.e(TAG, "called stopSelf on TrackingService from the endService handler");

                    }
                };

     }

}//end of trackingService

[Edit1]

public class TrackingService extends Service {

    private static final String TAG = TrackingService.class.getSimpleName();
    LocationManager             mlocManager;
    LocationListener            mlocListener;
    NfcScannerApplication       nfcscannerapplication;
    String carerID;

    Handler endServiceHandler;
    Runnable endServiceRunnable;

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {


        nfcscannerapplication = (NfcScannerApplication) getApplication();
        mlocManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
        mlocListener = new MyLocationListener();

        Log.e(TAG, "Service created and location manager and listener created");

        mlocManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, mlocListener);
        Log.e(TAG, "requesting location updates");

        enableMenuButtonsHandler();
        endServiceHandler.postDelayed(endServiceRunnable, 20 * 1000);

            return super.onStartCommand(intent, flags, startId);
    }



    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.e(TAG, "in onDestroy in LocationService class");
        mlocManager.removeUpdates(mlocListener);


    }








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

    private class MyLocationListener implements LocationListener {

        @Override
        public void onLocationChanged(Location loc) {


            Log.e(TAG, "in TrackingService onlocationChanged and about to send lon/lat " + loc.getLongitude() + " " + loc.getLatitude());


            DateTime dt = new DateTime();
            DateTimeFormatter df3 = DateTimeFormat.forPattern("yyyy-MM-dd H:mm:ss.SSS");
            String formattedNowTime3 = df3.print(dt);
            Log.e(TAG, "Time of location fix in TrackingServive = " + formattedNowTime3);


            Cursor c = nfcscannerapplication.loginValidate.queryAllFromCarer();

            if (c.getCount() > 0) {
                if(c.moveToLast()){

                carerID = c.getString(c.getColumnIndex(LoginValidate.C_CARER_ID));

                }
            }

             Log.e(TAG, "carer ID = " + carerID);

             mlocManager.removeUpdates(mlocListener);
             Log.e(TAG, "removed updates(TrackingService)");

             TrackingService.this.stopSelf();
             Log.e(TAG, "called stopSelf on TrackingService");

        }

        @Override
        public void onProviderDisabled(String provider) {
            // TODO Auto-generated method stub

        }

        @Override
        public void onProviderEnabled(String provider) {
            // TODO Auto-generated method stub

        }

        @Override
        public void onStatusChanged(String provider, int status, Bundle extras) {
            // TODO Auto-generated method stub

        }

    }// end of MyLocationListener


    public void enableMenuButtonsHandler() {

        endServiceHandler = new Handler();
        endServiceRunnable = new Runnable() {
            public void run() {

                endService();

            }

            private void endService() {

                 mlocManager.removeUpdates(mlocListener);
                 Log.e(TAG, "removed updates(TrackingService) from the endService handler");

                 TrackingService.this.stopSelf();
                 Log.e(TAG, "called stopSelf on TrackingService from the endService handler");

            }
        };

    }


}// end of service 

[Edit2]

@Override
    public int onStartCommand(Intent intent, int flags, int startId) {


        nfcscannerapplication = (NfcScannerApplication) getApplication();
        mlocManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
        mlocListener = new MyLocationListener();
        Log.e(TAG, "Service created and location manager and listener created");


            HandlerThread handlerThread = new HandlerThread("MyHandlerThread");
            handlerThread.start();
            Looper looper = handlerThread.getLooper();

            Handler handler = new Handler(looper);

        mlocManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, mlocListener, looper);
        Log.e(TAG, "requesting location updates");

        enableMenuButtonsHandler();
        endServiceHandler.postDelayed(endServiceRunnable, 20 * 1000);

            return super.onStartCommand(intent, flags, startId);
    }

[Edit3]

public class TrackingService extends Service {

    private static final String TAG = TrackingService.class.getSimpleName();
    LocationManager             mlocManager;
    LocationListener            mlocListener;
    NfcScannerApplication       nfcscannerapplication;
    String carerID;

    Handler endServiceHandler;
    Runnable endServiceRunnable;
    HandlerThread handlerThread;
    Looper looper;

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {


        nfcscannerapplication = (NfcScannerApplication) getApplication();
        mlocManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
        mlocListener = new MyLocationListener();
        Log.e(TAG, "Service created and location manager and listener created");


            Log.e(TAG, "creating handlerthread and looper");
            handlerThread = new HandlerThread("MyHandlerThread");
            handlerThread.start();
            looper = handlerThread.getLooper();





        mlocManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, mlocListener, looper);
        Log.e(TAG, "requesting location updates");

        enableMenuButtonsHandler();
        endServiceHandler.postDelayed(endServiceRunnable, 20 * 1000);

            return super.onStartCommand(intent, flags, startId);
    }



    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.e(TAG, "in onDestroy in LocationService class");
        mlocManager.removeUpdates(mlocListener);


    }







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

    private class MyLocationListener implements LocationListener {

        @Override
        public void onLocationChanged(Location loc) {


            Log.e(TAG, "in TrackingService onlocationChanged and about to send lon/lat " + loc.getLongitude() + " " + loc.getLatitude());


            DateTime dt = new DateTime();
            DateTimeFormatter df3 = DateTimeFormat.forPattern("yyyy-MM-dd H:mm:ss.SSS");
            String formattedNowTime3 = df3.print(dt);
            Log.e(TAG, "Time of location fix in TrackingServive = " + formattedNowTime3);


            Cursor c = nfcscannerapplication.loginValidate.queryAllFromCarer();

            if (c.getCount() > 0) {
                if(c.moveToLast()){

                carerID = c.getString(c.getColumnIndex(LoginValidate.C_CARER_ID));

                }
            }

             Log.e(TAG, "carer ID = " + carerID);

             nfcscannerapplication.loginWebservice.sendCarerLocation(carerID, formattedNowTime3, String.valueOf(loc.getLatitude()), String.valueOf(loc.getLongitude()));



             Log.e(TAG, "quiting handlerthread");
             handlerThread.quit();

             mlocManager.removeUpdates(mlocListener);
             Log.e(TAG, "removed updates(TrackingService)");

             TrackingService.this.stopSelf();
             Log.e(TAG, "called stopSelf on TrackingService");

        }

        @Override
        public void onProviderDisabled(String provider) {
            // TODO Auto-generated method stub

        }

        @Override
        public void onProviderEnabled(String provider) {
            // TODO Auto-generated method stub

        }

        @Override
        public void onStatusChanged(String provider, int status, Bundle extras) {
            // TODO Auto-generated method stub

        }

    }// end of MyLocationListener


    public void enableMenuButtonsHandler() {

        endServiceHandler = new Handler();
        endServiceRunnable = new Runnable() {
            public void run() {

                endService();

            }

            private void endService() {

                 mlocManager.removeUpdates(mlocListener);
                 Log.e(TAG, "removed updates(TrackingService) from the endService handler");

                 TrackingService.this.stopSelf();
                 Log.e(TAG, "called stopSelf on TrackingService from the endService handler");

                 Log.e(TAG, "quiting handlerthread from the endService handler");
                 handlerThread.quit();

            }
        };

    }


}// end of service
like image 862
turtleboy Avatar asked Dec 11 '22 09:12

turtleboy


1 Answers

As Pankaj Kumar notes, an IntentService is not an appropriate solution for cases where the work to be done is intrinsically asynchronous. Once onHandleIntent() returns, your service is destroyed.

Use a regular Service, register for locations in onStartCommand(), using a HandlerThread for processing the results (so you can pass its Looper into requestLocationUpdates()). Once your location is received, or a suitable timeout is reached, do your work and call stopSelf() on the service to shut it down.

like image 66
CommonsWare Avatar answered Dec 21 '22 11:12

CommonsWare