Harkish Harkish - 9 days ago 6
Android Question

Making the WakefulIntentService wait for location callback to be called

I am trying to build an app that has a service that sends the current location to a server every X minutes.

Looking at other posts in SO, found that the method outlined in commons-ware https://github.com/commonsguy/cwac-wakeful would work best. The demo2 app here works fine for me and it writes a message to Alarm.txt every x minutes.

I did the following modifications to "AppService.java" so that it attempts to get a location instead of what it does as a sample program.

public class AppService extends WakefulIntentService {

private Context context;
public AppService() {
super("AppService");
}

@Override
protected void doWakefulWork(Intent intent) {
// File log=new File(Environment.getExternalStorageDirectory(),
// "AlarmLog.txt");
//
// try {
// BufferedWriter out=new BufferedWriter(new FileWriter(log.getAbsolutePath(),
// log.exists()));
//
// out.write(new Date().toString());
// out.write("\n");
// out.close();
// Log.e("AppService", "wrote to log file");
// }
// catch (IOException e) {
// Log.e("AppService", "Exception appending to log file", e);
// }
context = this.getApplicationContext();
Log.e("AppService", "Attaempting to get location");
new GetLocation(context).execute();
}
}


My GetLocation.java looks like this

public class GetLocation {

private LocationManager locationManager;
private LocationListener locationListener;
private Context context;

public GetLocation(Context context) {
this.context = context;
}

public void execute() {
locationManager = (LocationManager) context
.getSystemService(Context.LOCATION_SERVICE);
locationListener = new LocationListener() {

@Override
public void onLocationChanged(Location location) {
new SendLocation2(location).execute();
locationManager.removeUpdates(locationListener);
}

@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

}
};
Log.e("AppService", "Registered to get location");
locationManager.requestLocationUpdates(
LocationManager.NETWORK_PROVIDER, 0, 0, locationListener);
}

}


Send location uses apache http client library to upload the location to the server.

When I run this I get the following in the logcat.

06-06 08:06:27.031: E/AppService(3161): Attaempting to get location
06-06 08:06:27.039: E/AppService(3161): Registered to get location


W/MessageQueue(3161): Handler (android.location.LocationManager$ListenerTransport$1) {41855e68} sending message to a Handler on a dead thread
W/MessageQueue(3161): java.lang.RuntimeException: Handler (android.location.LocationManager$ListenerTransport$1) {41855e68} sending message to a Handler on a dead thread
W/MessageQueue(3161): at android.os.MessageQueue.enqueueMessage(MessageQueue.java:294)
W/MessageQueue(3161): at android.os.Handler.enqueueMessage(Handler.java:618)
W/MessageQueue(3161): at android.os.Handler.sendMessageAtTime(Handler.java:587)
W/MessageQueue(3161): at android.os.Handler.sendMessageDelayed(Handler.java:558)
W/MessageQueue(3161): at android.os.Handler.sendMessage(Handler.java:495)
W/MessageQueue(3161): at android.location.LocationManager$ListenerTransport.onLocationChanged(LocationManager.java:218)
W/MessageQueue(3161): at android.location.ILocationListener$Stub.onTransact(ILocationListener.java:58)
W/MessageQueue(3161): at android.os.Binder.execTransact(Binder.java:351)
W/MessageQueue(3161): at dalvik.system.NativeStart.run(Native Method)


I looks like the app does not stay alive till its callback onLocationChanged() is called by the location manager. How can I fix this?

Answer

Looking at other posts in SO, found that the method outlined in commons-ware https://github.com/commonsguy/cwac-wakeful would work best.

Absolutely not. An IntentService of any form is inappropriate for your use case. An IntentService cannot register listeners, fork its own threads, or do anything that will continue running past the end of onHandleIntent(). Once onHandleIntent() returns, the service will shut down if there are no further commands to process, and that in turn can lead to your process being terminated.

For cases where you need to register a listener, use a regular Service, with your own managed WakeLock, where you control when the service shuts down.