我正在编写一个应用程序来获取每5秒的位置。我收到了这个错误。 java.lang.RuntimeException:无法在未调用Looper.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
}
}
}
答案 0 :(得分:0)
该错误实际上说该怎么做: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);
答案 1 :(得分:0)
首先,您错误地考虑了位置API - 您不需要每5秒轮询一次更新。您告诉LocationManager您要监听更新,它会在每次发生更新时告诉您更新。如果你告诉它将你的更新限制为每5秒一次,它将忽略或延迟更新以满足你的要求,但是如果没有任何给出,它会每隔五秒询问一次它会更频繁地给你更新
其次,你写的代码实际上并不是每五秒钟做一次。你开始的Thread
只是注册更新,等待五秒,然后退出 - 没有循环发生。幸运的是,除了不必要的额外线程和5秒延迟之外,实际上 是使用Location API的正确方法。
最后,对于您的实际问题:您获得RuntimeException的原因是您为LocationManager提供了一个LocationListener并告诉它(无意中)在rcvLocationThread
上执行其回调方法。 Looper
是一个用作消息泵的类。 Looper
在Thread
之上运行,并执行Handler
s给他们的工作。 Handler
在Looper
之上运行并接收消息和/或Runnable
,以及Looper
泵通过Handler
的队列并执行每个传入的物品。
如果在调用Looper
时未指定requestLocationUpdates
,则LocationManager会假定您正在通过 Looper
线程进行调用尝试将LocationListener
方法调用排入同一个线程。由于你的线程没有运行Looper
(在这种情况下它不应该),它实际上不能将回调排入队列,因此抛出异常。
那么 - 你做什么的?摆脱所有Thread
废话,并将RcvLocation.run()
方法中的所有内容放在new Thread(...).start()
末尾的onCreate
。此外,您的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
}
}