如何解决 SensorEventListener 运行单独线程时发生的任何问题?
How to resolve ANR problem occured in SensorEventListener operating separete thread?
我对 Java Android 编程一窍不通(实际上我对整个计算机编程一窍不通)。我打算在与服务的主线程分开的线程中制作加速度计传感器的 SensorEventListener。 onSencorChanged 方法在单独的线程中运行良好,但是,在运行服务后不久,就会出现 ANR。虽然发生了 ANR,但如果我不在 ANR 发生时终止并按 'wait' 保留应用程序 运行,应用程序将按我的预期进行。
找了很久解决方法,还是无法让我的应用停止ANR。
这是我使用 HandleThread 的代码。
public class SwingArmSensorService extends Service {
private SensorManager mSensorManager;
private Sensor mSensor;
private AccelerometerListenerInService listener;
private HandlerThread mSensorThread;
private Handler mSensorHandler;
private static SuperActivityUsingServiceMain activity;
private int mSteps;
private final String SWING_SENSOR_INTENT_STEP_DATA_NAME = "steps";
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (Looper.myLooper() == null) {
Looper.prepare();
}
mSensorThread = new HandlerThread("Sensor Thread", Thread.MAX_PRIORITY); //
mSensorThread.start(); //
mSensorHandler = new Handler(mSensorThread.getLooper());
listener = new AccelerometerListenerInService();
mSensorManager = (SensorManager)getSystemService(SENSOR_SERVICE);
mSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
mSensorManager.registerListener(listener, mSensor, SensorManager.SENSOR_DELAY_NORMAL, mSensorHandler);
mSteps = intent.getIntExtra(SWING_SENSOR_INTENT_STEP_DATA_NAME, 0);
Looper.loop();
...
}
private class AccelerometerListenerInService implements SensorEventListener {
private Handler mainHandler;
private float previousY, currentY;
private float x, y, z;
private final float THRESHOLD = 10f;
public AccelerometerListenerInService() {
mainHandler = new Handler(Looper.getMainLooper());
}
@Override
public void onSensorChanged(SensorEvent event) {
x = event.values[0];
y = event.values[1];
z = event.values[2];
currentY = y;
if (Math.abs(currentY - previousY) > THRESHOLD) {
mSteps++;
// Handle UI at main thread here
mainHandler.post(new Runnable() {
@Override
public void run() {
activity.setTextView(mSteps);
}
});
}
previousY = y;
}
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) { }
}
}
我本来打算只向您展示与代码问题相关的部分,但这是第一次 post 问题 Stack Overflow,所以如果我的代码太长,我很抱歉。
根本原因
在 Android 中,服务是 运行 在主线程上,它已经分配了一个 Looper。在您的代码中,当服务启动时,它会在主线程上调用 Looper.prepare()
和 Looper.loop()
,这将导致您的应用出现意外行为。
解决方案
从SwingArmSensorService
class
中删除以下代码
if (Looper.myLooper() == null) {
Looper.prepare();
}
Looper.loop();
因此,您的代码将是:
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
mSensorThread = new HandlerThread("Sensor Thread", Thread.MAX_PRIORITY); //
mSensorThread.start(); //
mSensorHandler = new Handler(mSensorThread.getLooper());
listener = new AccelerometerListenerInService();
mSensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
mSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
mSensorManager.registerListener(listener, mSensor, SensorManager.SENSOR_DELAY_NORMAL, mSensorHandler);
mSteps = intent.getIntExtra(SWING_SENSOR_INTENT_STEP_DATA_NAME, 0);
...
}
我对 Java Android 编程一窍不通(实际上我对整个计算机编程一窍不通)。我打算在与服务的主线程分开的线程中制作加速度计传感器的 SensorEventListener。 onSencorChanged 方法在单独的线程中运行良好,但是,在运行服务后不久,就会出现 ANR。虽然发生了 ANR,但如果我不在 ANR 发生时终止并按 'wait' 保留应用程序 运行,应用程序将按我的预期进行。 找了很久解决方法,还是无法让我的应用停止ANR。
这是我使用 HandleThread 的代码。
public class SwingArmSensorService extends Service {
private SensorManager mSensorManager;
private Sensor mSensor;
private AccelerometerListenerInService listener;
private HandlerThread mSensorThread;
private Handler mSensorHandler;
private static SuperActivityUsingServiceMain activity;
private int mSteps;
private final String SWING_SENSOR_INTENT_STEP_DATA_NAME = "steps";
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (Looper.myLooper() == null) {
Looper.prepare();
}
mSensorThread = new HandlerThread("Sensor Thread", Thread.MAX_PRIORITY); //
mSensorThread.start(); //
mSensorHandler = new Handler(mSensorThread.getLooper());
listener = new AccelerometerListenerInService();
mSensorManager = (SensorManager)getSystemService(SENSOR_SERVICE);
mSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
mSensorManager.registerListener(listener, mSensor, SensorManager.SENSOR_DELAY_NORMAL, mSensorHandler);
mSteps = intent.getIntExtra(SWING_SENSOR_INTENT_STEP_DATA_NAME, 0);
Looper.loop();
...
}
private class AccelerometerListenerInService implements SensorEventListener {
private Handler mainHandler;
private float previousY, currentY;
private float x, y, z;
private final float THRESHOLD = 10f;
public AccelerometerListenerInService() {
mainHandler = new Handler(Looper.getMainLooper());
}
@Override
public void onSensorChanged(SensorEvent event) {
x = event.values[0];
y = event.values[1];
z = event.values[2];
currentY = y;
if (Math.abs(currentY - previousY) > THRESHOLD) {
mSteps++;
// Handle UI at main thread here
mainHandler.post(new Runnable() {
@Override
public void run() {
activity.setTextView(mSteps);
}
});
}
previousY = y;
}
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) { }
}
}
我本来打算只向您展示与代码问题相关的部分,但这是第一次 post 问题 Stack Overflow,所以如果我的代码太长,我很抱歉。
根本原因
在 Android 中,服务是 运行 在主线程上,它已经分配了一个 Looper。在您的代码中,当服务启动时,它会在主线程上调用 Looper.prepare()
和 Looper.loop()
,这将导致您的应用出现意外行为。
解决方案
从SwingArmSensorService
class
if (Looper.myLooper() == null) {
Looper.prepare();
}
Looper.loop();
因此,您的代码将是:
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
mSensorThread = new HandlerThread("Sensor Thread", Thread.MAX_PRIORITY); //
mSensorThread.start(); //
mSensorHandler = new Handler(mSensorThread.getLooper());
listener = new AccelerometerListenerInService();
mSensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
mSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
mSensorManager.registerListener(listener, mSensor, SensorManager.SENSOR_DELAY_NORMAL, mSensorHandler);
mSteps = intent.getIntExtra(SWING_SENSOR_INTENT_STEP_DATA_NAME, 0);
...
}