艺术来源于生活,对我来说,编程也是一门艺术。今天发布这篇技术博客,就是我跟朋友在一次爬山过程中的争论,他跟我说那座山至少45度,我说没有,最多30度。我们彼此争论不休,于是我就想,为啥不写个手机程序来实际测量一下?于是,我的工作就开始了。

硬件基础

因为我暂时没有笔记本,所以就用了我的ZTE-U807N作为编写平台,它虽然配置较低,但有加速度传感器就够了。

编程工具

我选择移动端开发工具,使用AIDE作为集成开发环境(表示它真的很强大)。

算法思想

加速度传感器可以测量三坐标分量,即X, Y, Z坐标。XY平面是手机平面,Z坐标垂直手机平面,手机触屏朝上Z值为正。通过简单的数学推导可以得出坡度的余弦值等于|Z|比上X、Y、Z的矢量和的模。写成公式就是如下:
g = √(X²+Y²+Z²)
cosθ = |z|/g
于是,我就能够通过Z和g得出坡度θ的值。
由于加速度传感器采样速率很快,而且测量值不准,总是会变,所以我采样滑动平均算法,将各测量分量进行积累,然后求取平均值来消除误差,同时也可以消除手机静止时坡度数值跳变的问题。

数据结构

使用队列存储各分量数据,等数据积累完毕以后每来一个数据就出一个老数据。

框架编写

我需要2个界面,一个主界面,就是现地坡度;另一个是关于界面,就是软件说明、作者等等。具体如图所示:


首先在MainActivity放置一个TextView用于显示坡度。然后我给它加上一个SeekBar用于灵敏度调节,代码如下:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="fill_parent"android:layout_height="fill_parent"android:gravity="center"android:orientation="vertical"android:padding="20dp"><TextViewandroid:layout_height="wrap_content"android:layout_width="wrap_content"android:id="@+id/mainTextView1"android:textSize="80sp"/><LinearLayoutandroid:layout_height="wrap_content"android:layout_width="match_parent"android:orientation="horizontal"><TextViewandroid:layout_height="match_parent"android:text="灵敏度调节"android:textAppearance="?android:attr/textAppearanceMedium"android:layout_width="wrap_content"android:paddingRight="5dp"android:gravity="center_vertical"/><SeekBarandroid:layout_height="wrap_content"android:layout_width="match_parent"android:id="@+id/mainSeekBar1"/></LinearLayout>
</LinearLayout>

其次就是关于About界面,就是作者说明、版本啊等等,然后有个按钮,按下能够返回MainActivity界面。代码如下:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="fill_parent"android:layout_height="fill_parent"android:orientation="vertical"android:gravity="center"><TextViewandroid:layout_height="wrap_content"android:text="@string/version"android:textAppearance="?android:attr/textAppearanceLarge"android:layout_width="wrap_content"/><TextViewandroid:layout_height="wrap_content"android:text="@string/copy_right"android:textAppearance="?android:attr/textAppearanceMedium"android:layout_width="wrap_content"/><TextViewandroid:layout_height="wrap_content"android:text="@string/description"android:textAppearance="?android:attr/textAppearanceMedium"android:layout_width="wrap_content"/><Buttonandroid:layout_height="wrap_content"android:text="确定"android:layout_width="wrap_content"android:id="@+id/aboutButton1"/>
</LinearLayout>

然后我要有一个设置菜单,在MainActivity类里面加入onCreateOptionsMenu函数,代码如下:

@Override
public boolean onCreateOptionsMenu(Menu menu) {menu.add(Menu.FIRST, Menu.FIRST, Menu.FIRST, "关于").setIcon(android.R.drawable.ic_dialog_info);menu.add(Menu.FIRST+1, Menu.FIRST+1, Menu.FIRST+1, "退出").setIcon(android.R.drawable.ic_lock_power_off);return true;
}

当然要给菜单添加单击处理:

@Override
public boolean onOptionsItemSelected(MenuItem item) {if (item.getItemId() == Menu.FIRST) {/*关于界面*/Intent intent = new Intent();intent.setClass(MainActivity.this, About.class);startActivity(intent);}else if(item.getItemId() == Menu.FIRST + 1) {/*退出*/android.os.Process.killProcess(android.os.Process.myPid());finish();}return super.onOptionsItemSelected(item);
}

还有大多数软件有的连续按两次返回键退出程序:

/*long curent = 0;*/
@Override
public void onBackPressed() {if (System.currentTimeMillis() - current > 2000) { //如果两次按键时间大于2秒current = System.currentTimeMillis();Toast.makeText(this, "再按一次退出", Toast.LENGTH_SHORT).show();}else {android.os.Process.killProcess(android.os.Process.myPid());finish();}
}

最后就是在关于界面按键能够返回到主界面的功能:

@Overridepublic void onClick(View p1) {super.onBackPressed(); //实现按键返回上一活动
}

我偷了懒,调用父类的onBackPressed函数,就相当于按下返回键。

核心算法

首先是数据定义与初始化:

private long current;
private TextView tv = null;
private SeekBar sb = null;
private SeekListener seekl = null;  //自定义类
private SensorManager sm = null;
private Sensor as = null;
private SenListener sl = null;/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.main);current = 0;tv = (TextView)findViewById(R.id.mainTextView1);sb = (SeekBar)findViewById(R.id.mainSeekBar1);sb.setMax(3); //可以控制4个级别sb.setOnSeekBarChangeListener(seekl = new SeekListener());sm = (SensorManager)getSystemService(Service.SENSOR_SERVICE); //获取传感器管理器as = sm.getDefaultSensor(Sensor.TYPE_ACCELEROMETER); //获取加速度传感器sm.registerListener(sl = new SenListener(), as, SensorManager.SENSOR_DELAY_FASTEST); //注册传感器Toast.makeText(MainActivity.this, "请使手机平行于地面", Toast.LENGTH_LONG).show();
}

然后是传感器监听器的实现:

/**核心算法以及传感器监听器**/
private class SenListener implements SensorEventListener {private int sizeLimit; //缓冲区大小private Queue<Float> queX, queY, queZ; //各分量缓冲区private float sumX, sumY, sumZ; //和private float aveX, aveY, aveZ; //平均private float g; //矢量和private float gradient; //坡度SenListener() {sizeLimit = 100;queX = new LinkedList<>();queY = new LinkedList<>();queZ = new LinkedList<>();sumX = sumY = sumZ = 0;}void setLimit(int grade) {sizeLimit = 100 * (grade + 1); //SeekBar选择来控制缓冲区大小,据此可以调节灵敏度}private double grad2Deg (double grad) {return grad * 180 / Math.PI;}@Overridepublic void onSensorChanged(SensorEvent p1) {float x, y, z;x = p1.values[0];y = p1.values[1];z = p1.values[2];/*滑动平均算法核心部分*/sumX += x;sumY += y;sumZ += z;queX.offer(x);queY.offer(y);queZ.offer(z);while (queX.size() > sizeLimit) {sumX -= queX.poll();sumY -= queY.poll();sumZ -= queZ.poll();}aveX = sumX / queX.size();aveY = sumY / queX.size();aveZ = sumZ / queX.size();g = (float)Math.sqrt(aveX * aveX + aveY * aveY + aveZ * aveZ);gradient = (float)Math.acos(Math.abs(aveZ) / g);tv.setText(Math.round(grad2Deg(gradient)) + "º"); //弧度转为度}@Overridepublic void onAccuracyChanged(Sensor p1, int p2) {// TODO: Implement this method}@Overrideprotected void finalize() throws Throwable {// TODO: Implement this methodqueX = queY = queZ = null;super.finalize();}
}

结语

我最终编写出了坡度计,解决了我跟朋友的问题。我将我所想的与做的分享出来,写的也有些乱,如果有不明白的地方欢迎提问。另外,我将整个工程放到了我的百度网盘里,有兴趣的话欢迎下载,虽然是手机上建的,但它兼容Eclipse。http://pan.baidu.com/share/link?shareid=3657265547&uk=2315273780

转载于:https://www.cnblogs.com/hele-two/p/4563243.html

Android坡度计相关推荐

  1. Android面试计网面经大全【持续更新中。。。】

    前言 本篇文章为本人面试以及空闲时间整理的计网面试常见问题.供本人复习之用.分享给大家.大家可以评论补充哦! 因为面试常见问题一般都是网络层,传输层以及应用层.所以我就按自上而下的顺序,来分享 最后一 ...

  2. android 倒计 代码,2小时倒计时

    [android]代码库Handler handler = new Handler(); Runnable runnable = new Runnable() { @Override public v ...

  3. 自学Android!Android高级工程师面试题-字节跳动,附答案

    前言 大厂面试一直都是程序员圈内摸鱼时间津津乐道的话题,进大厂想必也是无数程序员的梦想. 关于"原理"的问题,几乎是现如今Android开发岗必问的问题,尤其在大厂面试中更为突出. ...

  4. 资深Android开发带你入门Framework,架构师必备技能

    开头 先说一下我大概的情况吧.渣本毕业,工作已经有快两年了,从高中就开始玩小破站.无论是学习还是日常放松都是在b站.大学主学的软件技术专业,所以,进大学校门那一刻起,去上海bilibili工作就在心里 ...

  5. 推测用户行为 程序员分享Android开发经验

    从G1上市到现在,市面上已经出现了至少30款Android手机.为什么至今依然有一些用户在抱怨Android不好用,在相关的开发中,什么才是真正值得关注的,开发的核心是什么?为什么移动应用需要格外关注 ...

  6. 2020.8.13 京东Android开发二面

    本次面试着重考察了计算机基础知识,Android相关均未涉及,及时暴露了我的一些漏洞,时间尚早,尽快补上来吧. 2020.8.13 京东Android开发二面 问题 聊项目 用过哪些数据库 数据库索引 ...

  7. Android自定义view之网易云推荐歌单界面

    系列文章目录 Android自定义view之网易云推荐歌单界面 文章目录 系列文章目录 前言 一.实现 1.自定义一个圆角图片控件(也可直接使用第三方框架) 2.进行布局摆设 3.图片切换动画效果 二 ...

  8. android培训课程!Kotlin可能带来的一个深坑,不吃透都对不起自己

    关于Android的近况 大家都知道,今年移动开发不那么火热了,完全没有了前两年Android开发那种火热的势头,如此同时,AI热火朝天,很多言论都说Android不行了.其实不光是Android,i ...

  9. Android开发必须会的技能!写给安卓软件工程师的3条建议,Android岗

    前言 首先介绍一下自己,计算机水本,考研与我无缘.之前在帝都某公司算法部实习,公司算大公司吧,然而个人爱好偏开发,大二的时候写个一个app,主要是用各种框架. 在开始复习知识点前,要确认以下 2 点: ...

最新文章

  1. Linux内核设计第五周学习总结 分析system_call中断处理过程
  2. BZOJ 2434 阿狸的打字机
  3. MySQL主从压_mysql主从配置
  4. 【转载】查看MSSQL数据库每个表占用的空间大小的方法
  5. (数据科学学习手札03)Python与R在随机数生成上的异同
  6. 平衡二叉树搜索二叉树
  7. SQL必知必会-使用游标
  8. PC下串口IO空间及其寄存器详解
  9. UIButton颜色渐变 titleLabel字体不显示
  10. Logback 深入分析
  11. LINUX下的C编程实战(一)――开发平台搭建
  12. sourceforge.net居然被劫持??
  13. 如何用计算机解锁苹果手机,教你怎么使用Apple Watch手表解锁苹果Mac电脑
  14. [回溯法] 求n个元素的集合的幂集 - 递归实现 - C语言
  15. Python 对称矩阵顺时针旋转90度
  16. CSS像素、物理像素、逻辑像素、设备像素比、PPI、Viewport
  17. SpringBoot实现邮箱发送验证码
  18. 计算机网络逻辑类故障实例,逻辑故障计算机网络论文
  19. log4j2 日志打两遍的问题
  20. SSH学习笔记(9)__Spring5_概述/简单程序/整合日志

热门文章

  1. UISearchBar控件
  2. 高强度的加密软件怎么制作
  3. TypeScript泛型约束
  4. 【ECharts学习】—实现我的第一个图表
  5. mysqlserver输入密码后闪退_iOS降级教程:iOS 14 后如何降级到ios13?
  6. 3个月定期存款利息怎么算?
  7. 一亿人民币是什么概念?
  8. 揭开发家致富的2个途径
  9. 如果不考虑钱和面子,你最想做什么工作?
  10. 为什么有些小老板,做了一辈子,还是没办法发展大?