Arun Babu
Arun Babu

Reputation: 259

Access android location from service?

I have a problem with requesting location updates from a thread started by service.

My application needs to get location updates from background service (without any UI thread). I will explain the structure of my application.

  1. It has a service started by Boot Receiver.
  2. In the onStartCommand() of service, its starts a scheduler thread.
  3. The scheduler thread requests location updates.

The problem is when scheduler calls locationMgr.requestLocationUpdates() Its says Can't create handler inside thread that has not called Looper.prepare() I have seen similar problems for others but cant find any solution. I heard we can call directly from service to get location updates without any problem but since I cant find a way to sleep service (like a scheduler thread), i guess i need a separate thread.

Please explain why this is happening? Does android require UI thread to request location? Is there any solution by changing my application structure?

Upvotes: 1

Views: 926

Answers (4)

Arun Babu
Arun Babu

Reputation: 259

I've fixed it by using a Handler.

  1. I created a handler.
  2. I put the service code in its handleMessage()
  3. Create a thread which sends empty message to handler at required interval (while loop).
  4. So when handler receives empty message, it runs the handleMessage() which contains actual scheduler loop

Upvotes: 0

Manmeet Singh Batra
Manmeet Singh Batra

Reputation: 467

I've used this and works fine : To get location in service

Service class here:

public class MyService extends Service {

    @Override
    public IBinder onBind(Intent arg0) {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public void onCreate() {
        // TODO Auto-generated method stub
        super.onCreate();

    }

    @Override
    public void onDestroy() {
        // TODO Auto-generated method stub
        super.onDestroy();
    }

    @Override
    public void onStart(Intent intent, int startId) {
        // TODO Auto-generated method stub
        super.onStart(intent, startId);

        // start location manager
        LocationDetermined objLocationDetemined = new LocationDetermined(this);
        objLocationDetemined.getlocation(this);
        objLocationDetemined.getRecentKnownLocation(this);

    }

Location class here:

public class LocationDetermined implements OnInitListener {

    String TAG = "LocationDeterminedClass";
private static LocationManager locationManager;
double Lat = 0.0;
double Long = 0.0;
GeoPoint geoPoint;
private Toast mToast;
Context appContext;
static MyLocationListener locationListener;

    public LocationDetermined(Context context) {
        this.appContext = context;

    }

    public MyLocationListener getlocation(Context appContext) {

        locationManager = (LocationManager) appContext
                .getSystemService(Context.LOCATION_SERVICE);
        locationListener = new MyLocationListener();
        Criteria criteria = new Criteria();
        criteria.setAccuracy(Criteria.ACCURACY_COARSE);
        String provider = locationManager.getBestProvider(criteria, true);

        Log.d(TAG, "------provider------" + provider);


        if (provider != null && locationManager.isProviderEnabled(provider)) {
            locationManager.requestLocationUpdates(provider, 0, 0,
                    locationListener);
        } else {
            Toast.makeText(appContext, "No provider available to get loctaion",
                    2000).show();
        }
        return locationListener;
    }



    private class MyLocationListener implements LocationListener {

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

        }

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

        }

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

        }

        public void onLocationChanged(final Location argLocation) {
            // TODO Auto-generated method stub
            if (argLocation != null) {
                Lat = argLocation.getLatitude();
                Long = argLocation.getLongitude();

                Log.e("OnLocationChanged:", "lat:" + Lat + "  long:" + Long);

                Log.d("service gps", "lat" + argLocation.getLatitude() + "-"
                        + argLocation.getLongitude());

                Constant.mLatitude = argLocation.getLatitude();
                Constant.mLongitude = argLocation.getLongitude();               
            }
        }
    }

    public GeoPoint getRecentKnownLocation(Context appContext) {
        Location locGps = locationManager
                .getLastKnownLocation(LocationManager.GPS_PROVIDER);
        Location locNet = locationManager
                .getLastKnownLocation(LocationManager.NETWORK_PROVIDER);

        Location locPassive = locationManager
                .getLastKnownLocation(LocationManager.PASSIVE_PROVIDER);
        if (locGps != null) {
            Lat = locGps.getLatitude();
            Long = locGps.getLongitude();

            Constant.mLatitude = locGps.getLatitude();
            Constant.mLongitude = locGps.getLongitude();

            geoPoint = new GeoPoint((int) (Lat * 1000000),
                    (int) (Long * 1000000));
            return geoPoint;

        } else if (locNet != null) {
            Lat = locNet.getLatitude();
            Long = locNet.getLongitude();

            Constant.mLatitude = locNet.getLatitude();
            Constant.mLongitude = locNet.getLongitude();

            geoPoint = new GeoPoint((int) (Lat * 1000000),
                    (int) (Long * 1000000));
            return geoPoint;

        }
        return geoPoint;
    }

    private void fetchedSavedLocationDetail(Context mContext) {

    }

    @Override
    public void onInit(int status) {
        // TODO Auto-generated method stub

    }

    public static void removeLocationListener() {

        locationManager.removeUpdates(locationListener);
    }

}

I used these variables in Constants class to store location public static double mLatitude = 0.0, mLongitude = 0.0;

start the service startService(new Intent(this, MyService.class));

Upvotes: 1

s.d
s.d

Reputation: 29436

Looper is what keeps polling a thread queue for Message's/Runnables (those posted via a Handler on that thread). UI thread has one by default. For custom threads, you need to set it up before you start the thread.

As mentioned in the example:

Class used to run a message loop for a thread. Threads by default do not have a message loop associated with them; to create one, call prepare() in the thread that is to run the loop, and then loop() to have it process messages until the loop is stopped.

Now, RequestLocationUpdates() needs a mechanism to deliver updates to your thread, but your thread doesn't have a Looper polling.

Consider Moving RequestLocationUpdates() and its corresponding removeUpdates() to Service thread. Most likely where service starts and stops.

Upvotes: 2

Naveen AH
Naveen AH

Reputation: 33

Reason for happening is : getLooper is connected to the UI of the context , but service is ackground process doesn't connect directly to UI. So your getting error.

resolution for your Issue:

1) place location classes in other package. 2) Import that package name. 3) Use one callback interface with in your package. 4) use the interface instance in your Service component. 5) It will work!!

Upvotes: 1

Related Questions