接收位置定期更新



我正在编写一个应用程序,每5秒获取位置。我收到这个错误。java.lang.RuntimeException:无法在未调用loop .prepare()的线程中创建处理程序。我已经搜索了这个错误代码。许多人认为有必要创建runOnUiThread()。然而,即使我注释掉了editTextShowLocation,意思是输出到ui,也会发生同样的错误。

非常感谢你的帮助。谢谢你。

下面是我的代码:
package com.example.celine.telemetryloop;
import android.app.Activity;
import android.content.Context;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import android.widget.Button;
import android.widget.EditText;
public class MainActivity extends Activity {
    private EditText editTextShowLocation;
    private Button buttonGetLocation;
    private LocationManager locManager;
    private LocationListener locListener = new MyLocationListener();
    private boolean gps_enabled = false;
    private boolean network_enabled = false;
    String TAG = "App";
    /**
     * Called when the activity is first created.
     */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        editTextShowLocation = (EditText) findViewById(R.id.editTextShowLocation);
        locManager = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE);
        Thread rcvLocationThread = new Thread(new RcvLocation());
        rcvLocationThread.start();
    }

    class RcvLocation implements Runnable {
        public void run() {
            try {
                gps_enabled = locManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
            } catch (Exception ex) {
            }
            try {
                network_enabled = locManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
            } catch (Exception ex) {
            }
            // don't start listeners if no provider is enabled
            if (!gps_enabled && !network_enabled) {
                Log.d(TAG, "Not Enabled!"); //to enable it for user.
            }
            if (gps_enabled) {
                locManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, locListener);
            }
            if (network_enabled) {
                locManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, locListener);
            }
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    class MyLocationListener extends Handler implements LocationListener {
        @Override
        public void onLocationChanged(Location location) {
            Log.d(TAG, "2");
            if (location != null) {
                // This needs to stop getting the location data and save the battery power.
                //locManager.removeUpdates(locListener);
                String londitude = "Londitude: " + location.getLongitude();
                String latitude = "Latitude: " + location.getLatitude();
                String altitiude = "Altitiude: " + location.getAltitude();
                String accuracy = "Accuracy: " + location.getAccuracy();
                String time = "Time: " + location.getTime();
                editTextShowLocation.setText(londitude + "n" + latitude + "n" + altitiude + "n" + accuracy + "n" + time);
            }
        }
        @Override
        public void onProviderDisabled(String provider) {
            // TODO Auto-generated method stub
        }
        @Override
        public void onProviderEnabled(String provider) {
            // TODO Auto-generated method stub
        }
        @Override
        public void onStatusChanged(String provider, int status, Bundle extras) {
            // TODO Auto-generated method stub
        }
    }
}

首先,您错误地考虑了位置api -您不需要每5秒轮询一次更新。你告诉LocationManager你想要监听更新,它会在每次更新发生时告诉你。如果你告诉它将你的更新限制为每5秒一次,它会为了满足你的要求而忽略或延迟更新,但如果没有更新,要求它每5秒更新一次并不能让它更频繁地给你更新。

第二,你写的代码实际上不会每五秒钟做任何事情。您启动的Thread只是注册更新,等待5秒钟,然后退出—没有发生循环。幸运的是,除了不必要的额外线程和5秒延迟之外,实际上是使用Location api的正确方法。

最后,你的实际问题:你得到你的RuntimeException的原因是,你给LocationManager一个LocationListener,并告诉它(无意中)在你的rcvLocationThread上执行它的回调方法。Looper是用作消息泵的类。Looper s运行在Thread s之上,执行Handler s交给它们的工作。Handler运行在Looper之上,接收消息和/或Runnable, Looper泵入Handler的队列,并执行每个传入的项目。

如果你在调用requestLocationUpdates时没有指定Looper,那么LocationManager假定你正在从一个Looper线程中调用,并尝试将LocationListener方法调用排队回同一个线程。因为你的线程没有一个Looper运行在它上面(在这种情况下它不应该),它实际上不能排队回调,所以抛出一个异常。

那么——你是怎么做的?去掉所有的Thread废话,把你在RcvLocation.run()方法中得到的所有东西放在onCreate末尾的new Thread(...).start()方法中。此外,您的MyLocationListener类不需要扩展Handler -只需让它实现LocationListener,您就可以了。回调将在主线程上执行(主线程已经有自己的Looper)。这很好,因为您正在修改视图(必须从主线程完成),并且由于您没有执行任何长时间运行的处理操作,因此看起来很安全。

public class MainActivity extends Activity {
    ... // variables and such
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        editTextShowLocation = (EditText) findViewById(R.id.editTextShowLocation);
        locManager = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE);
        setupLocationUpdates();
    }

    private void setupLocationUpdates() {
        try {
            gps_enabled = locManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
        } catch (Exception ex) { /* tsk tsk, empty catch block */ }
        try {
            network_enabled = locManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
        } catch (Exception ex) { /* tsk tsk, empty catch block */ }
        // don't start listeners if no provider is enabled
        if (!gps_enabled && !network_enabled) {
            Log.d(TAG, "Not Enabled!"); //to enable it for user.
        }
        if (gps_enabled) {
            locManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, locListener);
        }
        if (network_enabled) {
            locManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, locListener);
        }
    }
    class MyLocationListener implements LocationListener {
        @Override
        public void onLocationChanged(Location location) {
            // do your stuff
        }
        // all the other required callback methods
    }
}

错误实际上说该怎么做:Looper.prepare()没有在您的线程内调用。参考这个SO答案:https://stackoverflow.com/a/16886486/798406

它基本上说你必须把Looper.prepare()放在Runnable的run()方法中。但是,您应该避免使用Thread.sleep。相反,您可以使用另一个处理程序,并在5秒后发布延迟消息:

private class Poller implements Runnable {
    /**
     * {@inheritDoc}
     * 
     * @see java.lang.Runnable#run()
     */
    @Override
    public void run() {
        // Do something
        long pollingDelay = 5000;
        mHandler.postDelayed(this, pollingDelay);
    }
}
// Start the handler
mPollingRunnable = new Poller();
mHandler.post(mPollingRunnable);

最新更新