原文链接:http://blog.csdn.net/warren288/article/details/43274647

1,功能实现

确定当前设备朝向的方式有两种,一种是是直接使用 方向传感器 Sensor.TYPE_ORIENTATION,另一种是结合使用Sensor.TYPE_ACCELEROMETER和Sensor.TYPE_MAGNETIC_FIELD;前一种已经不建议使用了,因为它无法根据应用的横竖屏与设备的自然方向调整结果方向,且精确度不如后一种方式。

后一种方式的实现如下,比较关键的地方都写注释了。

[java] view plain copy
  1. <pre name="code" class="java">    /**
  2. * 方向传感器中心。<br>
  3. * 使用方法为:创建对象后使用 {@link #init(Activity)} 初始化上下文环境,使用
  4. * {@link #registerOrientationListener(IListener)} 注册
  5. * 方向变化监听器,使用完毕后(一般在 {@link #init(Activity)}中所使用 {@link Activity}
  6. * 销毁时), {@link #unregister()}取消本类内部注册的 {@link SensorEventListener}
  7. * @author yangsheng
  8. * @date 2015年1月28日
  9. */
  10. private static class SensorCenter {
  11. private float[] accelerValues = new float[3];
  12. private float[] magneticValues = new float[3];
  13. private final SensorEventListener sensorListener = new SensorEventListener() {
  14. @Override
  15. public void onSensorChanged(SensorEvent event) {
  16. switch (event.sensor.getType()) {
  17. // 深度复制,可避免部分设备下 SensorManager.getRotationMatrix 返回false的问题
  18. case Sensor.TYPE_ACCELEROMETER:
  19. for (int i = 0; i < 3; i++) {
  20. accelerValues[i] = event.values[i];
  21. }
  22. if (listener != null) {
  23. listener.onCall(getAngle());
  24. }
  25. break;
  26. case Sensor.TYPE_MAGNETIC_FIELD:
  27. for (int i = 0; i < 3; i++) {
  28. magneticValues[i] = event.values[i];
  29. }
  30. break;
  31. case Sensor.TYPE_GYROSCOPE:
  32. break;
  33. default:
  34. break;
  35. }
  36. }
  37. @Override
  38. public void onAccuracyChanged(Sensor sensor, int accuracy) {
  39. }
  40. };
  41. private SensorManager sensorManager;
  42. private Activity activity;
  43. private IListener<Float> listener;
  44. private int axis_x;
  45. private int axis_y;
  46. public SensorCenter init(Activity activity) {
  47. this.activity = activity;
  48. this.sensorManager = (SensorManager) this.activity
  49. .getSystemService(Context.SENSOR_SERVICE);
  50. // 注册三个传感器监听,加速度传感器、磁场传感器、陀螺仪传感器。
  51. // 陀螺仪传感器是可选的,也没有实际用处,但是在部分设备上,如果没注册它,会导致
  52. // SensorManager.getRotationMatrix 返回false
  53. sensorManager.registerListener(sensorListener,
  54. sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER),
  55. SensorManager.SENSOR_DELAY_UI);
  56. sensorManager.registerListener(sensorListener,
  57. sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD),
  58. SensorManager.SENSOR_DELAY_UI);
  59. sensorManager.registerListener(sensorListener,
  60. sensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE),
  61. SensorManager.SENSOR_DELAY_UI);
  62. initIn();
  63. return this;
  64. }
  65. private void initIn() {
  66. // 根据当前上下文的屏幕方向调整与自然方向的相对关系。
  67. // 当设备的自然方向是竖直方向(比如,理论上说所有手机的自然方向都是都是是竖直方向),而应用是横屏时,
  68. // 需要将相对设备自然方向的方位角转换为相对水平方向的方位角。
  69. WindowManager wm = (WindowManager) activity.getSystemService(Context.WINDOW_SERVICE);
  70. Display dis = wm.getDefaultDisplay();
  71. int rotation = dis.getRotation();
  72. axis_x = SensorManager.AXIS_X;
  73. axis_y = SensorManager.AXIS_Y;
  74. switch (rotation) {
  75. case Surface.ROTATION_0:
  76. break;
  77. case Surface.ROTATION_90:
  78. axis_x = SensorManager.AXIS_Y;
  79. axis_y = SensorManager.AXIS_MINUS_X;
  80. break;
  81. case Surface.ROTATION_180:
  82. axis_x = SensorManager.AXIS_X;
  83. axis_y = SensorManager.AXIS_MINUS_Y;
  84. break;
  85. case Surface.ROTATION_270:
  86. axis_x = SensorManager.AXIS_MINUS_Y;
  87. axis_y = SensorManager.AXIS_X;
  88. break;
  89. default:
  90. break;
  91. }
  92. }
  93. /**
  94. * 注册方向变换监听
  95. * @param listener, {@link IListener#onCall(Object)}
  96. *            中的参数为相对正北方向的方位角,范围:-180~180
  97. */
  98. public void registerOrientationListener(IListener<Float> listener) {
  99. this.listener = listener;
  100. }
  101. /**
  102. * 取方位角
  103. * @return
  104. */
  105. private float getAngle() {
  106. float[] inR = new float[9];
  107. // 第一个是方向角度参数,第二个参数是倾斜角度参数
  108. SensorManager.getRotationMatrix(inR, null, accelerValues, magneticValues);
  109. float[] outR = new float[9];
  110. float[] orientationValues = new float[3];
  111. // 根据当前上下文的屏幕方向调整与自然方向的相对关系。
  112. // 当设备的自然方向是竖直方向(比如,理论上说所有手机的自然方向都是都是是竖直方向,而有些平板的自然方向是水平方向),而应用是横屏时,
  113. // 需要将相对设备自然方向的方位角转换为相对水平方向的方位角。
  114. SensorManager.remapCoordinateSystem(inR, axis_x, axis_y, outR);
  115. SensorManager.getOrientation(outR, orientationValues);
[java] view plain copy
  1. <span style="white-space:pre">            </span>// <span style="font-family: Arial, Helvetica, sans-serif;">orientationValues里的值都是弧度值,需要转换为角度值</span>
  2. return (float) Math.toDegrees(orientationValues[0]);
  3. }
  4. /**
  5. * 取消注册的传感器监听
  6. */
  7. public void unregister() {
  8. try {
  9. sensorManager.unregisterListener(sensorListener);
  10. } catch (Exception e) {
  11. LogTool.exception(e);
  12. }
  13. }
  14. }

2,常见问题

最常见的问题是 SensorManager.getRotationMatrix 返回false,传进去的第一个参数没有被正确赋值,于是最终获得方位角就是0。
这个问题出现的原因一般有以下几种:
(1)在注册的传感器监听器的 onSensorChanged 中没有使用深复制,而是直接使用浅复制 accelerValues = event.values; 这种情况下,部分设备可以正确地取到最终的方位角,但是部分设备下就会出现  SensorManager.getRotationMatrix  失败的问题。应该是不同设备的系统使用了不同的方式重写了Android的这一段代码导致的。
(2)在注册传感器监听器时,只注册了 Sensor.TYPE_ACCELEROMETER和Sensor.TYPE_MAGNETIC_FIELD两种监听器,没有注册 Sensor.TYPE_GYROSCOPE; 这种情况下,部分设备中可以正确地取到最终的方位角,但是部分设备下就会出现上述问题。
由于不同设备的自然方向可能不同,有些是竖直方向有些是水平方向,而应用可能是竖屏可能是横屏,所以在很多情况下,我们需要在取方位角之前先将自然坐标系投影到我们需要的实际坐标系上去,使用SensorManager.remapCoordinateSystem 方法。
附:

利用android手机自带的加速度传感器和磁场传感器确定手机的姿态

android使用磁场传感器和加速度传感器确定当前朝向(即:方位角),以及常见问题的解决办法相关推荐

  1. android 生成泛型对象,java android解析多层含有泛型对象的json数据获取不到泛型类型解析失败解决办法...

    ####问题描述 * java 解析多层含有泛型对象的json数据获取不到泛型类型 * 如果将泛型改成实际的类型就能正常解析 * 如果不改成实际的类型泛型数据被解析成com.google.gson.i ...

  2. 分享一个android debug模式,出现 waiting for debugger把界面卡住,取巧的解决办法

    使用android studio开发程序时,有时会出现 waiting for debugger 卡住界面,软件无法正常debug运行的情况,很多网友分享了一些解决办法,比如: 1 打开cmd进入命令 ...

  3. Android Studio更新成2.3以后Gradle大坑拯救,gradle安装异常解决办法

    Studio更新一次能要了我半条命,我的Studio每次都很幸运地出现这样那样的问题,这次也不例外. 更新完2.3以后就一直Refreshing.而且大脑迟钝的我一个多小时以后才发现-- 就像这样 好 ...

  4. Android之导入项目提示Android requires compiler compliance level 5.0 or 6.0. Found ‘1.8‘ instead解决办法

    1.问题 导入项目eclipse提示如下: Android requires compiler compliance level 5.0 or 6.0. Found '1.8' instead 2.解 ...

  5. 关于android开发时,发生Error infalting classa com.baidu.mapapi.map.MapView的解决办法

    1.问题描述:百度地图SDK中 Error: infalting classa com.baidu.mapapi.map.MapView . 2.解决办法:通过1个多小时的上网搜索,最终发现很多网友之 ...

  6. Android ADT插件更新后程序运行时抛出java.lang.VerifyError异常解决办法

    当我把Eclipse中的 Android ADT插件从21.1.0更新到22.0.1之后,安装后运行程序抛出java.lang.VerifyError异常. 经过调查,终于找到了一个有效的解决办法: ...

  7. Android项目运行junit测试类时出现错误Internal Error (classFileParser.cpp:3494)的解决办法...

    以前的项目运行好好的,升级了ADT后,进行junit测试时出现错误: # # A fatal error has been detected by the Java Runtime Environme ...

  8. 刺激战场android闪退,刺激战场总是闪退怎么办?刺激战场闪退解决办法

    刺激战场总是闪退怎么办?刺激战场闪退解决办法 2018-09-05 17:00:01 刺激战场在推出之后,成为手机上最火热的游戏之一,但是有玩家在下载游戏之后运行,会闪退,进入不了游戏,这是怎么回事呢 ...

  9. Android U盘插拔监听详细版以及U盘写入权限解决办法

    首先,代码都是用在项目里的,肯定是可用的.踩过的一些坑一起会写在下面.如果有更好的方法,请告知我. 用广播接收U盘插板的状态,其中插板的判断可以加入"android.intent.actio ...

最新文章

  1. Java程序员面试如何超常发挥?
  2. 12_信息熵,信息熵公式,信息增益,决策树、常见决策树使用的算法、决策树的流程、决策树API、决策树案例、随机森林、随机森林的构建过程、随机森林API、随机森林的优缺点、随机森林案例
  3. MindManager脑图之项目管理甘特图
  4. opengl层次建模_层次建模简介
  5. Vi编辑器的基本使用方法及vi和Vim的区别【ZT】
  6. Shell获取多行输入并输出每行的第3个字符
  7. JCR分区 与 中科院分区的分区方法
  8. C语言齿轮参数计算程序,C语言程序实现齿轮基本参数几何尺寸计算.pdf
  9. java中json转map
  10. 第三方登录(百度账号登录)
  11. [案例]信息巨头Carfax如何打造数据产品
  12. 教你利用clustalw和blat解决接头问题问题
  13. Tensorflow-Gpu安装 基于gtx1060
  14. 在CSDN中如何快速简单方便的免费下载资料
  15. 关于dubbo的rpc基于传输层一说
  16. python matplotlib 显示中文的问题
  17. StringUtils使用
  18. Hive 与 Hbase表映射(内部表与外部表),Hbase常用命令
  19. SML(standard ML)入门学习(1)
  20. AGC 自动增益控制

热门文章

  1. 【机器学习】十大机器学习基础算法
  2. 每日英语-20230221
  3. HDU 6441 Find Integer
  4. 【算法学习】前缀树Trie
  5. 判断某日是一年中的第几天
  6. 分布式计算原理之分布式协调与同步(1)——分布式事务
  7. 计算机处理器ghz,电脑CPU的GHZ代表什么?比如1.7GHZ、2.2GHZ??
  8. intel(R)wireless-ac 9462感叹号,WLAN消失,电脑连不上网解决办法
  9. ocr文字识别技术有什么意义
  10. JavaScript知识点整理(十三)- DOM -(2)操作元素