开发者

Android: requestLocationUpdates throws exception

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(); } }

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜