1

我试图通过 Android 中的 GPS 定期获取用户位置并将数据发送到远程数据库,但我得到了例外: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

4 回答 4

2

使用消息循环器的正确方法在其文档中描述,此处有代码示例

于 2011-08-05T19:34:19.777 回答
2

最后解决方案是:

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

最后是 LocationListener 接口的 LocationHelper:

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 分钟后,会有数百个线程。

有人知道为什么吗?

于 2011-08-08T09:08:10.217 回答
1

我建议你做的是

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())。

于 2011-08-05T20:22:28.043 回答
1

您可以使用这种方法:

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

于 2012-01-31T09:26:53.383 回答