I have curious problem, in my application, the GPS-positioning takes quite a long time (as it tends to do) and therefore I wanted to run it as its own thread while the user is making choices in other views.
My structure is that I have a "main" view that is always active in the background, then the user is shown a series of views in which he or she makes a few choices. In the end, the user is presented with a result based on the choices made and the current position. All of this works, but I wanted to move the GPS-bit to its own thread so that the user wouldn't have to wait for it to finish.
All of the user's choices and the GPS coordinates is stored in a singleton called CurrentLogEntry. All communication between the different parts of the program is performed through it.
I created a handleMessage(Message msg)
override in the main view and then I implemented this function in Main.java:
void startGPSThread() {
Thread t = new Thread() {
LocationManager locationManager = (LocationManager) getSystemService(LOCATION_SERVICE);
boolean isDebug = CurrentLogEntry.getInstance().isDebug();
// Define a listener that responds to location updates
LocationListener locationListener = new LocationListener() {
public void onStatusChanged(String provider, int status, Bundle extras) {
/* This is called when the GPS status changes */
String tag = "onStatusChanged, ";
switch (status) {
case LocationProvider.OUT_OF_SERVICE:
Log.w(tag, "Status Changed: Out of Service");
break;
case LocationProvider.TEMPORARILY_UNAVAILABLE:
Log.w(tag, "Status Changed: Temporarily Unavailable");
break;
case LocationProvider.AVAILABLE:
break;
}
}
public void onProviderEnabled(String provider) {
}
public void onProviderDisabled(String provider) {
// This is called if the GPS is disabled in settings.
// Bring up the GPS settings
Intent intent = new Intent(
android.provider.Settings.ACTION_LOCATION_SOURCE_SETTINGS);
startActivity(intent);
}
public void onLocationChanged(Location location) {
// Once a location has been received, ignore all other position
// updates.
locationManager.removeUpdates(locationListener);
locationManager.removeUpdates(this);
// Make sure that the received location is a valid one,
// otherwise show a warning toast and hit "back".
if (location == null) {
String warningString = "Location was unititialized!";
if (isDebug) {
Toast.makeText(getApplicationContext(),
warningString,
Toast.LENGTH_LONG).show();
}
KeyEvent kev = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_BACK);
onKeyDown(KeyEvent.KEYCODE_BACK, kev);
}
CurrentLogEntry.getInstance().setUserLatitude(location.getLatitude());
CurrentLogEntry.getInstance().setUserLongitude(location.getLongitude());
//Send update to the main thread
int result = 0;
if (location.getLatitude() == 0 || location.getLongitude() == 0) {
result = -1;
}
messageHandler.sendMessage(Message.obtain(messageHandler, result));
}
};
@Override
public void run() {
locationManager.requestLocationUpdates(
LocationManager.GPS_PROVIDER, 0, 0, locationListener);
// Wait until a position has bee acquired.
while(!CurrentLogEntry.getInstance().isReadyToCalculate()){
try {
wait(250);
} catch (InterruptedException ex) {
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
};
t.start();
}
This function is called in Main.onCreate()
.
Unfortunately, this doesn't work at all. The program crashes as soon as it reaches locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, locationListener);
and that has me completely stumped.
Can anyone enlighten me as to why this won't run as a background thread? Also, do I really need the wait-polling at the end to ensure that the thread stays alive until it receives its data? The GPS bit worked just fine before I wanted to put it in a thread of its own, so what in the world am I doing wrong?