Reputation: 259
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.
onStartCommand()
of service, its starts a scheduler thread.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
Reputation: 259
I've fixed it by using a Handler.
handleMessage()
handleMessage()
which contains actual scheduler loopUpvotes: 0
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
Reputation: 29436
Looper
is what keeps polling a thread queue for Message
's/Runnable
s (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.
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
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