I'm trying to get periodically the user position via GPS in Android and send the data to a remote DB, but I get the exception: Can't create handler inside thread that has not called Looper.prepare()
.
The method that retrieves the position is in a remote service, and it's pretty basic:
private void dumpLocationLog() {
Loca开发者_高级运维tionManager lm = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
Looper.myLooper().prepare();
lm.requestLocationUpdates(LocationManager.GPS_PROVIDER, 1000L, 500.0f ,this);
retrieveUserId();
sendData(user_id);
}
I tried calling Looper.myLooper().prepare();
but it still does not work.
I guess I have to implement a Looper
here but I don't know how as I'm still pretty newbie with Android.
This is the full code of my service:
public class LocationLoggingService extends Service {
String latString, lngString;
Double latitude, longitude;
Date durationDate;
String user_id;
public String username;
private Handler serviceHandler;
private Task myTask = new Task();
@Override
public IBinder onBind(Intent i) {
Log.d(getClass().getSimpleName(), "onBind()");
username = i.getStringExtra("username");
return myRemoteLocationServiceStub;
}
private IMyRemoteLocationLoggingService.Stub myRemoteLocationServiceStub = new IMyRemoteLocationLoggingService.Stub() {
public void dumpLocationLog() throws RemoteException {
LocationLoggingService.this.dumpLocationLog();
}
};
@Override
public void onCreate() {
super.onCreate();
Log.d(getClass().getSimpleName(), "onCreate()");
}
@Override
public void onDestroy() {
super.onDestroy();
serviceHandler.removeCallbacks(myTask);
serviceHandler = null;
Log.d(getClass().getSimpleName(), "onDestroy()");
}
@Override
public void onStart(Intent intent, int startId) {
username = intent.getStringExtra("username");
super.onStart(intent, startId);
serviceHandler = new Handler();
serviceHandler.postDelayed(myTask, 1000L);
Log.d(getClass().getSimpleName(), "onStart()");
}
class Task implements Runnable {
public void run() {
try {
myRemoteLocationServiceStub.dumpLocationLog();
} catch (RemoteException e) {
e.printStackTrace();
}
serviceHandler.postDelayed(this, 5000L);
Log.i(getClass().getSimpleName(), "Calling the dumpLocationLog");
}
}
public void retrieveUserId() {
ArrayList<NameValuePair> postParameters = new ArrayList<NameValuePair>();
postParameters.add(new BasicNameValuePair("username", username));
String response = null;
try {
response = CustomHttpClient.executeHttpPost(
"http://10.0.2.2/science/getUserId.php", postParameters);
String res = response.toString();
res = res.replaceAll("\\s+", "");
if (!res.equals("0")) {
Log.d(getClass().getSimpleName(),
"Successfully retrieved user_id");
user_id = res;
} else {
Log.d(getClass().getSimpleName(), "Error retrieving user_id");
}
} catch (Exception e) {
}
}
private void sendData(String user_id) {
ArrayList<NameValuePair> postParameters = new ArrayList<NameValuePair>();
postParameters.add(new BasicNameValuePair("user_id", user_id));
postParameters.add(new BasicNameValuePair("latitude", latString));
postParameters.add(new BasicNameValuePair("longitude", lngString));
String response = null;
try {
response = CustomHttpClient.executeHttpPost(
"http://10.0.2.2/science/sendLocationData.php",
postParameters);
String res = response.toString();
res = res.replaceAll("\\s+", "");
if (res.equals("1")) {
Log.d(getClass().getSimpleName(), "Insertado en DB!");
} else {
Log.d(getClass().getSimpleName(), "Error insertando en la DB");
}
} catch (Exception e) {
}
}
LocationListener myLocationListener = new LocationListener () {
@Override
public void onLocationChanged(Location location) {
if (location != null) {
android.os.Debug.waitForDebugger();
latitude = location.getLatitude();
longitude = location.getLongitude();
latString = Double.toString(latitude);
lngString = Double.toString(longitude);
Log.d("Location: ", getClass().getSimpleName());
Log.d(latString, getClass().getSimpleName());
Log.d(lngString, getClass().getSimpleName());
}
}
@Override
public void onProviderDisabled(String provider) {
}
@Override
public void onProviderEnabled(String provider) {
}
@Override
public void onStatusChanged(String provider, int status, Bundle extras) {
}
};
private void dumpLocationLog() {
LocationManager lm = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
lm.requestLocationUpdates(LocationManager.GPS_PROVIDER, 1000L, 500.0f, myLocationListener);
retrieveUserId();
sendData(user_id);
}
public static String create_datestring(String timestring)
throws java.text.ParseException {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss",
Locale.US);
Date dt = null;
Calendar c = Calendar.getInstance();
try {
dt = sdf.parse("2011-03-01 17:55:15");
c.setTime(dt);
System.out.println(c.getTimeInMillis());
System.out.println(dt.toString());
} catch (ParseException e) {
System.err.println("There's an error in the Date!");
}
return dt.toString();
}
}
Thanks a lot in advance!
The proper way to use the message looper is described in its doc with a code sample here
Well finally the solution is:
Class LoggingService.java (this is my service):
private void dumpLocationLog() {
new DumpLocationLog(context, latString, lngString).start();
Log.d(latString, getClass().getSimpleName());
Log.d(lngString, getClass().getSimpleName());
retrieveUserId();
sendData(user_id);
}
Then in DumpLocationLog.java:
public class DumpLocationLog extends Thread {
LocationManager lm;
LocationHelper loc;
String latString, lngString = null;
public DumpLocationLog(Context context, String latString, String lngString) {
loc = new LocationHelper();
lm = (LocationManager)context.getSystemService(Context.LOCATION_SERVICE);
}
public void run() {
Looper.prepare();
lm.requestLocationUpdates(LocationManager.GPS_PROVIDER, 1000L, 500.0f, loc);
Looper.loop();
}
}
Then finally the LocationHelper for the LocationListener interface:
public class LocationHelper implements LocationListener {
public String latString, lngString;
public Double latitude, longitude;
@Override
public void onLocationChanged(Location location) {
if (location != null) {
latitude = location.getLatitude();
longitude = location.getLongitude();
LocationLoggingService.latString = Double.toString(latitude);
LocationLoggingService.lngString = Double.toString(longitude);
}
}
@Override
public void onProviderDisabled(String provider) {
}
@Override
public void onProviderEnabled(String provider) {
}
@Override
public void onStatusChanged(String provider, int status, Bundle extras) {
}
}
It works like a charm but I have realized, that when listening for locations, it's creating threads non-stop and never closing the former ones; I mean that every time it checks for location, it creates a new thread and after X minutes, there are hundreds of threads.
Anybody knows why?
What I was suggesting you do was
class DumpLocationLog extends Thread
{
public void run()
{
LocationManager lm = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
lm.requestLocationUpdates(LocationManager.GPS_PROVIDER, 1000L, 500.0f ,/* FIXME this */);
retrieveUserId();
sendData(user_id);
}
}
Then, from wherever you had been calling dumpLocationLog(), use runOnUiThread(new DumpLocationLog()) instead.
You can use this approach:
class DumpLocationLog extends Thread
{
public void run()
{
Looper.prepare();
mLooper = Looper.myLooper();
lm.requestLocationUpdates(LocationManager.GPS_PROVIDER, 1000L, 500.0f ,mLooper);
retrieveUserId();
sendData(user_id);
Looper.loop();
}
public void stop()
{
mLooper.quit();
}
}
精彩评论