问题描述
我有一个Android应用程序,是一个使用旋转矢量传感器。看了评论<一个href="http://stackoverflow.com/questions/21357100/android-rotation-vector-sensor-error?newreg=d6e19da4953c4261aea95505aef32ae6">here,我看到,新的API等级,SensorEvent包含4-5值,而不是3我的code使用的arraycopy的数据。
I have an Android app that's using the Rotation Vector sensor. Having read the comment here, I see that with newer API levels, the SensorEvent contains 4-5 values, instead of 3. My code uses an arraycopy for the data.
lastRotVal是一个类的成员,并初始化为大小[3]的数组。下面是的code响应传感器事件的相关部分。
lastRotVal is a class member and is initialized as an array of size [3]. Here's the relevant parts of the code responding to the sensor events.
public void onSensorChanged(SensorEvent event) {
System.arraycopy(event.values, 0, lastRotVal, 0, 3); //Hardcoded size
lastRotValSet = true;
updateDisplay(event);
}
private void updateDisplay(SensorEvent event){
if (lastRotValSet){
float[] rotation = new float[9];
float[] orientation = new float[3];
SensorManager.getRotationMatrixFromVector(rotation, lastRotVal);
SensorManager.getOrientation(rotation, orientation);
double pitch = orientation[1];
double roll = orientation[2];
//Do stuff with roll and pitch
}
}
我已经很难codeD只使用在arraycopy 3个值研究。这似乎是工作的老一代和新API的水平。这是为了维护版本之间的兼容性最好的方式,或者我可以做的更好的东西?
I've hardcoded in only using 3 values in the arraycopy. It seems to be working on both older and the new API levels. Is this the best way to maintain that compatibility between versions, or could I be doing something better?
编辑:正如所接受的答案,促使这个问题的抛出:IllegalArgumentException显然出现一个错误的三星设备,而不是一般的API版本的API中的结果。所以,我要补充的是我最初遇到错误在三星Galaxy SIII的事实。
As stated by the accepted answer, the IllegalArgumentException that prompted this question apparently arises as a consequence of a bug in the API on Samsung devices, not the general API version. So I'll add the fact that my initial error was encountered on a Samsung Galaxy SIII.
推荐答案
<一个href="http://stackoverflow.com/questions/21357100/android-rotation-vector-sensor-error?newreg=d6e19da4953c4261aea95505aef32ae6">The帖子您引用实际上指的是在一些三星设备(银河S4,银河注3)错误 - 看的。实际上,你不应该做的SDK二者之间的特殊处理此code工作在正常的设备。但是,唉,碎片...
The post that you reference actually refers to a bug in a few Samsung devices (Galaxy S4, Galaxy Note 3) - see this Android Developer list post. You actually shouldn't have to do any special handling between SDK levels for this code to work on normal devices. But, alas, fragmentation...
<一个href="https://src.chromium.org/viewvc/chrome/trunk/src/content/public/android/java/src/org/chromium/content/browser/DeviceMotionAndOrientation.java?pathrev=246398"相对=nofollow>铬处理这个问题通过截断阵列中,如果大小大于4:
Chromium handles this issue by truncating the array if the size is greater than 4:
if (values.length > 4) {
// On some Samsung devices SensorManager.getRotationMatrixFromVector
// appears to throw an exception if rotation vector has length > 4.
// For the purposes of this class the first 4 values of the
// rotation vector are sufficient (see crbug.com/335298 for details).
if (mTruncatedRotationVector == null) {
mTruncatedRotationVector = new float[4];
}
System.arraycopy(values, 0, mTruncatedRotationVector, 0, 4);
getOrientationFromRotationVector(mTruncatedRotationVector);
} else {
getOrientationFromRotationVector(values);
}
不过,我在我的应用程序 GPSTest 发现,这种解决方案似乎并没有工作,银河S3(见Github的问题这里)。
However, I found in my app GPSTest that this solution didn't seem to work on the Galaxy S3 (see Github issue here).
所以,我最终只能截断阵列上抛出的抛出:IllegalArgumentException
设备。这也避免了额外System.arraycopy(),除非它的绝对必要的。
So, I ended up only truncating the array on devices that throw the IllegalArgumentException
. This also avoids the extra System.arraycopy() unless its absolutely necessary.
下面是在code片段(也支持与API的水平低于姜饼(即,之前被引入所述ROTATION_VECTOR传感器时)的设备取向传感器,并处理重新映射的坐标系统的取向变化),它使用一类成员 mTruncateVector
被初始化为假
:
Here's the code snippet (that also supports orientation sensors on devices with API levels less than Gingerbread (i.e., prior to when the ROTATION_VECTOR sensor was introduced), and handles remapping the coordinate system for orientation changes), which uses a class member mTruncateVector
that is initialized to false
:
@TargetApi(Build.VERSION_CODES.GINGERBREAD)
@Override
public void onSensorChanged(SensorEvent event) {
double orientation = Double.NaN;
double tilt = Double.NaN;
switch (event.sensor.getType()) {
case Sensor.TYPE_ROTATION_VECTOR:
// Modern rotation vector sensors
if (!mTruncateVector) {
try {
SensorManager.getRotationMatrixFromVector(mRotationMatrix, event.values);
} catch (IllegalArgumentException e) {
// On some Samsung devices, an exception is thrown if this vector > 4 (see #39)
// Truncate the array, since we can deal with only the first four values
Log.e(TAG, "Samsung device error? Will truncate vectors - " + e);
mTruncateVector = true;
// Do the truncation here the first time the exception occurs
getRotationMatrixFromTruncatedVector(event.values);
}
} else {
// Truncate the array to avoid the exception on some devices (see #39)
getRotationMatrixFromTruncatedVector(event.values);
}
int rot = getWindowManager().getDefaultDisplay().getRotation();
switch (rot) {
case Surface.ROTATION_0:
// No orientation change, use default coordinate system
SensorManager.getOrientation(mRotationMatrix, mValues);
// Log.d(TAG, "Rotation-0");
break;
case Surface.ROTATION_90:
// Log.d(TAG, "Rotation-90");
SensorManager.remapCoordinateSystem(mRotationMatrix, SensorManager.AXIS_Y,
SensorManager.AXIS_MINUS_X, mRemappedMatrix);
SensorManager.getOrientation(mRemappedMatrix, mValues);
break;
case Surface.ROTATION_180:
// Log.d(TAG, "Rotation-180");
SensorManager
.remapCoordinateSystem(mRotationMatrix, SensorManager.AXIS_MINUS_X,
SensorManager.AXIS_MINUS_Y, mRemappedMatrix);
SensorManager.getOrientation(mRemappedMatrix, mValues);
break;
case Surface.ROTATION_270:
// Log.d(TAG, "Rotation-270");
SensorManager
.remapCoordinateSystem(mRotationMatrix, SensorManager.AXIS_MINUS_Y,
SensorManager.AXIS_X, mRemappedMatrix);
SensorManager.getOrientation(mRemappedMatrix, mValues);
break;
default:
// This shouldn't happen - assume default orientation
SensorManager.getOrientation(mRotationMatrix, mValues);
// Log.d(TAG, "Rotation-Unknown");
break;
}
orientation = Math.toDegrees(mValues[0]); // azimuth
tilt = Math.toDegrees(mValues[1]);
break;
case Sensor.TYPE_ORIENTATION:
// Legacy orientation sensors
orientation = event.values[0];
break;
default:
// A sensor we're not using, so return
return;
}
}
@TargetApi(Build.VERSION_CODES.GINGERBREAD)
private void getRotationMatrixFromTruncatedVector(float[] vector) {
System.arraycopy(vector, 0, mTruncatedRotationVector, 0, 4);
SensorManager.getRotationMatrixFromVector(mRotationMatrix, mTruncatedRotationVector);
}
和注册在 onResume传感器()
:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD) {
// Use the modern rotation vector sensors
Sensor vectorSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ROTATION_VECTOR);
mSensorManager.registerListener(this, vectorSensor, 16000); // ~60hz
} else {
// Use the legacy orientation sensors
Sensor sensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ORIENTATION);
if (sensor != null) {
mSensorManager.registerListener(this, sensor,
SensorManager.SENSOR_DELAY_GAME);
}
}
全面实施是这里Github上。
这篇关于如何确保Android的API级别RotationVector之间的兼容性?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!