Android: requestLocationUpdates создает исключение
Я пытаюсь периодически получать данные о местоположении пользователя через GPS в Android и отправлять данные в удаленную БД, но я получаю исключение: Can't create handler inside thread that has not called Looper.prepare()
,
Метод, который извлекает позицию в удаленном сервисе, и он довольно простой:
private void dumpLocationLog() {
LocationManager lm = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
Looper.myLooper().prepare();
lm.requestLocationUpdates(LocationManager.GPS_PROVIDER, 1000L, 500.0f ,this);
retrieveUserId();
sendData(user_id);
}
Я пробовал звонить Looper.myLooper().prepare();
но это все равно не работает. Я думаю, я должен реализовать Looper
здесь, но я не знаю, как, поскольку я все еще довольно новичок с Android.
Это полный код моего сервиса:
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();
}
}
Заранее большое спасибо!
4 ответа
Ну, наконец, решение:
Класс LoggingService.java (это мой сервис):
private void dumpLocationLog() {
new DumpLocationLog(context, latString, lngString).start();
Log.d(latString, getClass().getSimpleName());
Log.d(lngString, getClass().getSimpleName());
retrieveUserId();
sendData(user_id);
}
Затем в 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();
}
}
Затем, наконец, LocationHelper для интерфейса LocationListener:
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) {
}
}
Это работает как шарм, но я понял, что при прослушивании локаций он создает нити без остановок и никогда не закрывает прежние; Я имею в виду, что каждый раз, когда он проверяет местоположение, он создает новый поток, и через X минут появляются сотни потоков.
Кто-нибудь знает почему?
Правильный способ использования сообщения Looper описан в его документе с примером кода здесь
Я предлагал тебе сделать
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);
}
}
Затем, откуда бы вы ни вызывали dumpLocationLog(), используйте взамен runOnUiThread(new DumpLocationLog()).
Вы можете использовать этот подход:
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();
}
}