安卓应用开发学习:手机摇一摇功能应用尝试--摇骰子和摇红包
一、引言
前几天,我发布的日志《安卓应用开发学习:查看手机传感器信息》记录了如何查看手机传感器的信息,通过上述的方法,可以看到我的OPPO手机支持19种传感器。本篇日志就记录一下常见的加速度传感器的典型应用——“摇一摇”功能。本应用通过加速度传感器来实现摇骰子或摇红包。最终效果如下:
摇骰子

摇红包

游戏结束

二、功能实现
加速传感器是最常见的传感器之一,有很多应用的摇手机功能就是用到了这个传感器。本次通过学习相关资料,在我的手机上实现了摇骰子和摇红包两个小应用,并且在摇动手机的过程中手机还会振动。大体的实现方法如下:
1.实现振动功能
1.1先要在AndroidManifest.xml文件中添加如下权限。
<uses-permission android:name="android.permission.VIBRATE" />
1.2 在你创建的Activity中申明一个Vibrator对象。
private Vibrator mVibrator;
1.3在需要实现手机振动功能的代码块中,执行vibrate()方法。
mVibrator.vibrate(300); // 系统检测到摇一摇事件后,震动手机提示用户
该方法参数有两种形式:
一是形如 mVibrator.vibrate(300) 的单参数,表示让手机持续振动指定的毫秒数;
二是形如 mVibrator.vibrate({500, 200, 500}, -1) 的双参数,表示先振动500毫秒,然后停止200毫秒,再振动500毫秒。第二个参数为-1表示无循环,为正数,表示循环次数。
2.摇一摇功能的实现
2.1在你创建的Activity中申明一个SensorManager对象。
private SensorManager mSensorMgr;
2.2重写活动页面的onResume方法,在该方法中注册传感器监听事件,并指定待监听的传感器类型为加速度传感器。
@Overrideprotected void onResume() {super.onResume();// 给加速度传感器注册传感监听器mSensorMgr.registerListener(this,mSensorMgr.getDefaultSensor(Sensor.TYPE_ACCELEROMETER),SensorManager.SENSOR_DELAY_NORMAL);}
2.3重写活动页面的onPause方法,在该方法中注销监听器。
@Overrideprotected void onPause() {super.onPause();mSensorMgr.unregisterListener(this); // 注销当前活动的传感监听器}
2.3编写一个传感器事件监听器,该监听器继承自SensorEventListener。
在活动页面名称后面添加“implements SensorEventListener”(如下),
public class ShakeActivity extends AppCompatActivity implements SensorEventListener {...}
然后按Alt + Enter,Android Studio 自动添加onSensorChanged方法和onAccuracyChanged方法。
onSensorChanged方法在感应信息变化时触发,业务逻辑就写在这里。在本应用中添加的代码是检测手机晃动的幅度是否大于阀值,一旦大于阀值,就让手机振动500毫秒。
onAccuracyChanged方法在精度改变时触发,一般无需处理。
@Overridepublic void onSensorChanged(SensorEvent event) {if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) { // 加速度变更事件// values[0]:X轴,values[1]:Y轴,values[2]:Z轴float[] values = event.values;if ((Math.abs(values[0]) > 15 || Math.abs(values[1]) > 15|| Math.abs(values[2]) > 15)) {mVibrator.vibrate(300); // 系统检测到摇一摇事件后,震动手机提示用户}}}@Overridepublic void onAccuracyChanged(Sensor sensor, int accuracy) {// 当传感器精度改变时回调该方法,一般无需处理}
3.游戏模式的选择
3.1本应用支持2种游戏模式,因此在界面设计上用到了RadioGroup和RadioButton。
<TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="center_vertical"android:gravity="center_horizontal"android:text="游戏模式:" /><RadioGroupandroid:id="@+id/rg_mode"android:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="horizontal"><RadioButtonandroid:id="@+id/rb_dice"android:layout_width="80dp"android:layout_height="20dp"android:checked="true"android:text="摇骰子" /><RadioButtonandroid:id="@+id/rb_welfare"android:layout_width="80dp"android:layout_height="20dp"android:text="摇红包" /></RadioGroup>
3.2在活动页面声明如下变量:
private int mMode; // 游戏模式private final int MODE_DICE = 0; // 游戏模式1:摇骰子private final int MODE_WELFARE = 1; // 游戏模式2:摇红包private boolean mState = false; // 游戏状态private int diceCount; // 统计摇骰子次数private int welfareNumber; // 统计红包个数private final int[] welfareArr = {1, 5, 10} ; // 红包,可根据情况调整
3.2在活动页面中编写单选按钮组事件监听器,该监听器继承自RadioGroup.OnCheckedChangeListener。通过单选按钮的改变触发响应事件,在onCheckedChanged方法中编写游戏模式变更的逻辑代码。
@Overridepublic void onCheckedChanged(RadioGroup group, int checkedId) {// 根据单选按钮结果,设置游戏模式if (checkedId == R.id.rb_dice) {mMode = MODE_DICE; // 摇骰子模式} else if (checkedId == R.id.rb_welfare) {mMode = MODE_WELFARE; // 摇红包模式}}
4.游戏的执行逻辑
4.1游戏模式选择。默认是选中了摇一摇模式。
4.2点“开始”按钮。当前是非游戏状态;将变量diceCount和welfareNumber都设为0;将游戏状态变量mState设为Ture;页面中显示“请开始摇手机”;将按钮文本改为停止。游戏过程中游戏模式可随时切换,不会终止游戏。
4.3只有mState为Ture时摇动手机,才会进行检测。当检测到有效摇动时,手机会振动300毫秒,并执行startGame方法(延时300毫秒后执行,避免此方法实际执行次数与振动次数有大的差异。
4.4startGame方法中首先检查游戏模式。
如果是摇骰子模式,则产生三个1-6的随机数(设定为三个骰子)。将本次的结果显示在页面上,并将摇骰子次数统计变量diceCount加1。
如果是摇红包模式,则产生一个1-10的随机数,将该随机数与数组welfareArr中的元素进行对比,如果该随机数在数组中,则在页面中显示中奖信息。获得红包统计变量welfareNumber加1。
5.游戏状态下点“停止”按钮,结束游戏。将按钮文本改为开始;页面中显示摇骰子次数和获得红包个数。
三、代码展示
最终的代码如下:
1. 界面设计文件 activity_shake.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"tools:context=".ShakeActivity"><TextViewandroid:id="@+id/tv_title"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginTop="20dp"android:text="摇一摇"android:textSize="28sp"android:textStyle="bold"app:layout_constraintEnd_toEndOf="parent"app:layout_constraintStart_toStartOf="parent"app:layout_constraintTop_toTopOf="parent" /><LinearLayoutandroid:id="@+id/ll_mode"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginStart="10dp"android:layout_marginTop="30dp"android:layout_marginEnd="10dp"android:orientation="horizontal"app:layout_constraintEnd_toEndOf="parent"app:layout_constraintStart_toStartOf="parent"app:layout_constraintTop_toBottomOf="@+id/tv_title"><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="center_vertical"android:gravity="center_horizontal"android:text="游戏模式:" /><RadioGroupandroid:id="@+id/rg_mode"android:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="horizontal"><RadioButtonandroid:id="@+id/rb_dice"android:layout_width="80dp"android:layout_height="20dp"android:checked="true"android:text="摇骰子" /><RadioButtonandroid:id="@+id/rb_welfare"android:layout_width="80dp"android:layout_height="20dp"android:text="摇红包" /></RadioGroup></LinearLayout><Buttonandroid:id="@+id/btn_start"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginTop="30dp"android:text="开始"app:layout_constraintEnd_toEndOf="parent"app:layout_constraintStart_toStartOf="parent"app:layout_constraintTop_toBottomOf="@+id/ll_mode" /><TextViewandroid:id="@+id/tv_shake"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginTop="30dp"android:textSize="17sp"app:layout_constraintEnd_toEndOf="parent"app:layout_constraintStart_toStartOf="parent"app:layout_constraintTop_toBottomOf="@+id/btn_start" /></androidx.constraintlayout.widget.ConstraintLayout>
2.逻辑代码 ShakeActivity.java
import androidx.appcompat.app.AppCompatActivity;import android.content.Context;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Bundle;
import android.os.Handler;
import android.os.Vibrator;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.RadioGroup;
import android.widget.TextView;import java.util.Arrays;
import java.util.Locale;
import java.util.Random;public class ShakeActivity extends AppCompatActivity implements SensorEventListener,RadioGroup.OnCheckedChangeListener, View.OnClickListener {private final static String TAG = "ShakeActivity";private TextView tv_shake; // 声明一个文本视图对象private SensorManager mSensorMgr; // 声明一个传感管理器对象private Vibrator mVibrator; // 声明一个震动器对象private Button btn_start; // 开始按钮private int mMode; // 游戏模式private final int MODE_DICE = 0; // 游戏模式1:摇骰子private final int MODE_WELFARE = 1; // 游戏模式2:摇红包private boolean mState = false; // 游戏状态private int diceCount; // 统计摇骰子次数private int welfareNumber; // 统计红包个数private final int[] welfareArr = {1, 5, 10} ; // 红包 , 20, 50, 100, 500, 1000@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_shake);// 游戏模式选择按钮组RadioGroup rg_mode = findViewById(R.id.rg_mode);rg_mode.setOnCheckedChangeListener(this);tv_shake = findViewById(R.id.tv_shake);btn_start = findViewById(R.id.btn_start);btn_start.setOnClickListener(this); // 开始按钮点击监听// 从系统服务中获取传感管理器对象mSensorMgr = (SensorManager) getSystemService(Context.SENSOR_SERVICE);// 从系统服务中获取震动器对象mVibrator = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);mMode = MODE_DICE; // 单选按钮初始状态选中的遥骰子}@Overrideprotected void onPause() {super.onPause();mSensorMgr.unregisterListener(this); // 注销当前活动的传感监听器}@Overrideprotected void onResume() {super.onResume();// 给加速度传感器注册传感监听器mSensorMgr.registerListener(this,mSensorMgr.getDefaultSensor(Sensor.TYPE_ACCELEROMETER),SensorManager.SENSOR_DELAY_NORMAL);}@Overridepublic void onSensorChanged(SensorEvent event) {if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) { // 加速度变更事件// values[0]:X轴,values[1]:Y轴,values[2]:Z轴float[] values = event.values;if ((Math.abs(values[0]) > 30 || Math.abs(values[1]) > 30|| Math.abs(values[2]) > 30)) {if (mState) {mVibrator.vibrate(300); // 系统检测到摇一摇事件后,震动手机提示用户new Handler().postDelayed(() -> {// 延时后要执行的代码startGame();}, 300); // 延迟时间毫秒}}}}@Overridepublic void onAccuracyChanged(Sensor sensor, int accuracy) {// 当传感器精度改变时回调该方法,一般无需处理}@Overridepublic void onCheckedChanged(RadioGroup group, int checkedId) {// 根据单选按钮结果,设置游戏模式if (checkedId == R.id.rb_dice) {mMode = MODE_DICE; // 摇骰子模式} else if (checkedId == R.id.rb_welfare) {mMode = MODE_WELFARE; // 摇红包模式}}@Overridepublic void onClick(View v) {if (v.getId() == R.id.btn_start) {if (mState) { // 点击时处于游戏状态btn_start.setText("开始");String info = String.format(Locale.CHINESE, "%s%d次,%s%d个。","本次摇骰子", diceCount, "获得红包", welfareNumber);tv_shake.setText(info);} else { // 点击时处于非游戏状态diceCount = 0;welfareNumber = 0;tv_shake.setText("请开始摇手机");btn_start.setText("停止");}mState = !mState;}}private void startGame() {String info = ""; // 检查游戏模式if (mMode == MODE_DICE) { // 摇骰子// 设定有3个骰子,产生3个1-6的随机数Random random = new Random();int dice1 = random.nextInt(6) + 1;int dice2 = random.nextInt(6) + 1;int dice3 = random.nextInt(6) + 1;info = String.format(Locale.CHINESE,"%s%d,%d,%d。", "您摇出的骰子点数是:",dice1, dice2, dice3);diceCount +=1;} else if (mMode == MODE_WELFARE) { // 摇红包int lottery;info = "很遗憾,您没有中奖";// 生成一个0-10的随机数int randomNumber = (int)(Math.random() * 11); // 1001Log.d(TAG, "随机数为:" + randomNumber);// 检查该随机数是否在红包列表中boolean isInArray = Arrays.stream(welfareArr).anyMatch(n -> n == randomNumber);if (isInArray) {lottery = randomNumber;info = String.format(Locale.CHINESE,"%s%d%s", "恭喜您中了", lottery,"元!");welfareNumber +=1;}}tv_shake.setText(info);}
}
相关文章:
安卓应用开发学习:手机摇一摇功能应用尝试--摇骰子和摇红包
一、引言 前几天,我发布的日志《安卓应用开发学习:查看手机传感器信息》记录了如何查看手机传感器的信息,通过上述的方法,可以看到我的OPPO手机支持19种传感器。本篇日志就记录一下常见的加速度传感器的典型应用——“摇一摇”功…...
HTML中的<fieldset>标签元素框的使用
HTML 提供的 <fieldset> 标签用于在表单中分组相关元素。 <fieldset> 标签会在相关元素周围绘制一个框。 <legend> 标签为 fieldset 元素定义标题。 语法如下: <fieldset><legend>标题</legend><!-- 元素内容... -->…...
Linux驱动入门实验班——SR501红外模块驱动(附百问网视频链接)
目录 一、工作方式 二、接口图 三、编写思路 1.构造file_operations结构体 2.实现read函数 3.编写入口函数 4.编写中断处理函数 5.编写出口函数 6.声明出入口函数以及协议 四、源码 五、课程链接 一、工作方式 SR501人体红外感应模块有两种工作模式: …...
windows C++- Com技术简介(上)
在介绍C和winrt与COM组件技术的关系之前,有必要介绍一下com组件技术,这项技术比较古老,但是它一直作为windows的基石存在。COM 是一类独立于平台且面向对象的分布式系统,用于创建可交互的二进制软件组件。 COM 技术是 Microsoft O…...
Jenkins持续集成工具学习
一、从装修厨房看项目开发效率优化 二、持续集成工具 三、JavaEE项目部署方式对比 四、JenkinsSVN持续集成环境搭建 五、JenkinsGitHub持续集成环境搭建...
Redis:查询是否包含某个字符/字符串之三
上一篇:Redis:查询是否包含某个字符/字符串之二-CSDN博客 摘要: 遍历key,在跟进value的类型遍历value是否包含指定字符串 search_strings ,这里使用redis-py库,默认只能处理utf-8编码,如果存在…...
【Redis】数据类型详解及其应用场景
目录 Redis 常⻅数据类型预备知识基本全局命令小结 数据结构和内部编码单线程架构引出单线程模型为什么单线程还能这么快 Redis 常⻅数据类型 Redis 提供了 5 种数据结构,理解每种数据结构的特点对于 Redis 开发运维⾮常重要,同时掌握每种数据结构的常⻅…...
PARA-Drive:设计并行模型实现端到端自动驾驶
论文链接 https://openaccess.thecvf.com/content/CVPR2024/papers/Weng_PARA-Drive_Parallelized_Architecture_for_Real-time_Autonomous_Driving_CVPR_2024_paper.pdfhttps://openaccess.thecvf.com/content/CVPR2024/papers/Weng_PARA-Drive_Parallelized_Architecture_fo…...
vs2022 x64 C/C++和汇编混编 遇到的坑
vs2022 x64 C/C和汇编混编 遇到的坑 遇到的问题二、问题复现1.出错代码2.问题分析2.1 堆栈对齐问题 3.解决方案 总结奇数和偶数个寄存器的影响为什么 sub rsp, 8 对奇数个寄存器有用?结论 遇到的问题 0x00007FFFFAE24A29 (msvcp140.dll)处(位于 TestCompileConsole…...
PHP概述、环境搭建与基本语法讲解
目录 【学习目标、重难点知识】 什么是网站? 1. PHP 介绍 1.1. PHP 概述 1.1.1. PHP 是什么? 1.1.2. PHP 都能做什么? 1.2. PHP 环境搭建 1.2.1. PhpStudy 2. PHP 基本语法 2.1. PHP 语法入门 2.1.1. 第一个 PHP 程序 2.1.2. PHP …...
实现信创Linux麦克风摄像头录制(源码,银河麒麟、统信UOS)
随着信创国产化浪潮的来临,在国产操作系统上的应用开发的需求越来越多,其中一个就是需要在银河麒麟或统信UOS上实现录制摄像头视频和麦克风声音,将它们录制成一个mp4文件。那么这个要如何实现了? 一. 技术方案 要完成这些功能&a…...
深度学习9--目标检测
1.概念介绍 目标检测不仅可以检测数字,而且可以检测动物的种类、汽车的种类等。例如,自动驾驶车辆需要自动识别前方物体是车辆还是行人,需要自动识别道路两 旁的指示牌和前方的红绿灯颜色。对于自动检测的算法,有两个要求…...
第131天:内网安全-横向移动Kerberos 攻击SPN扫描WinRMWinRSRDP
案例一:域横向移动-RDP-明文&NTLM RDP利用的三种方式 1.直接在当前被控主机上进行远程连接 2.建立节点进行连接 3.端口转发,(访问当前主机的2222端口等于访问目标的3389) 第一种方式(动静太大) 直接利用被控主机进行远程连接…...
微信小程序的四种弹窗使用
在做小程序的过程中,弹窗也算是非常实用的功能了,这几天写的几个功能就用到了弹窗,也可能是初学者的问题,比较菜,想找一个可以带图片的自定义的弹窗,,这里简单介绍一下官方封装好的四个弹窗…...
我的第一个CUDA程序
MatAdd算法 实现两个矩阵对应元素相加 #include <stdio.h> #include <stdlib.h>// 矩阵加法函数 void MatAdd(int height, int width) {// 在主机内存中为 A、B 和 C 分配内存float* A (float*)malloc(height * width * sizeof(float));float* B (float*)malloc…...
workerman下的webman路由浏览器跨域的一种问题
软件版本 "php": ">7.2", "workerman/webman-framework": "^1.5.0",问题情景 使用“分组路由”做API接口前后端分离跨域,在接口测试工具调试是能正常获取数据的;但在网页浏览器上调试就遇到了CORS、404的错…...
Windows11 -MASKRCNN-部署测试
文章目录 Detectron2环境配置搭建python 环境安装Cuda \CUDNN 、PyTorch、 torchvision、cudatoolkit1、Cuda \CUDNN2、 PyTorch、 torchvision、cudatoolkit进入python测试:错误信息 3、detectron2环境在安装detecteron中,遇到报错:编译的时…...
函数(子程序)的常见、易混淆概念详解【对初学者有帮助】
C语⾔中的函数也被称做子程序,意思就是⼀个完成某项特定的任务的⼀小段代码。 C语⾔标准中提供了许多库函数,点击下面的链接可以查看c语言的库函数和头文件。 C/C官⽅的链接:https://zh.cppreference.com/w/c/header 目录 一、函数头与函…...
TiDB-从0到1-DM工具
TiDB从0到1系列 TiDB-从0到1-体系结构TiDB-从0到1-分布式存储TiDB-从0到1-分布式事务TiDB-从0到1-MVCCTiDB-从0到1-部署篇TiDB-从0到1-配置篇TiDB-从0到1-集群扩缩容TiDB-从0到1-数据导出导入TiDB-从0到1-BR工具 一、DM原理 支持全量抽取数据\检测新的数据变化同步到下游实例…...
AppScan——Web 应用安全扫描的得力工具
一、引言 在当今数字化时代,Web 应用成为企业业务的重要支撑,但同时也面临着各种安全威胁。AppScan 作为一款专业的 Web 应用安全扫描工具,为保障 Web 应用的安全性提供了有力的支持。本文将对 AppScan 进行详细介绍,包括其功能、…...
XML Group端口详解
在XML数据映射过程中,经常需要对数据进行分组聚合操作。例如,当处理包含多个物料明细的XML文件时,可能需要将相同物料号的明细归为一组,或对相同物料号的数量进行求和计算。传统实现方式通常需要编写脚本代码,增加了开…...
XCTF-web-easyupload
试了试php,php7,pht,phtml等,都没有用 尝试.user.ini 抓包修改将.user.ini修改为jpg图片 在上传一个123.jpg 用蚁剑连接,得到flag...
装饰模式(Decorator Pattern)重构java邮件发奖系统实战
前言 现在我们有个如下的需求,设计一个邮件发奖的小系统, 需求 1.数据验证 → 2. 敏感信息加密 → 3. 日志记录 → 4. 实际发送邮件 装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其…...
java_网络服务相关_gateway_nacos_feign区别联系
1. spring-cloud-starter-gateway 作用:作为微服务架构的网关,统一入口,处理所有外部请求。 核心能力: 路由转发(基于路径、服务名等)过滤器(鉴权、限流、日志、Header 处理)支持负…...
中南大学无人机智能体的全面评估!BEDI:用于评估无人机上具身智能体的综合性基准测试
作者:Mingning Guo, Mengwei Wu, Jiarun He, Shaoxian Li, Haifeng Li, Chao Tao单位:中南大学地球科学与信息物理学院论文标题:BEDI: A Comprehensive Benchmark for Evaluating Embodied Agents on UAVs论文链接:https://arxiv.…...
OkHttp 中实现断点续传 demo
在 OkHttp 中实现断点续传主要通过以下步骤完成,核心是利用 HTTP 协议的 Range 请求头指定下载范围: 实现原理 Range 请求头:向服务器请求文件的特定字节范围(如 Range: bytes1024-) 本地文件记录:保存已…...
视频字幕质量评估的大规模细粒度基准
大家读完觉得有帮助记得关注和点赞!!! 摘要 视频字幕在文本到视频生成任务中起着至关重要的作用,因为它们的质量直接影响所生成视频的语义连贯性和视觉保真度。尽管大型视觉-语言模型(VLMs)在字幕生成方面…...
【服务器压力测试】本地PC电脑作为服务器运行时出现卡顿和资源紧张(Windows/Linux)
要让本地PC电脑作为服务器运行时出现卡顿和资源紧张的情况,可以通过以下几种方式模拟或触发: 1. 增加CPU负载 运行大量计算密集型任务,例如: 使用多线程循环执行复杂计算(如数学运算、加密解密等)。运行图…...
CRMEB 框架中 PHP 上传扩展开发:涵盖本地上传及阿里云 OSS、腾讯云 COS、七牛云
目前已有本地上传、阿里云OSS上传、腾讯云COS上传、七牛云上传扩展 扩展入口文件 文件目录 crmeb\services\upload\Upload.php namespace crmeb\services\upload;use crmeb\basic\BaseManager; use think\facade\Config;/*** Class Upload* package crmeb\services\upload* …...
【HTTP三个基础问题】
面试官您好!HTTP是超文本传输协议,是互联网上客户端和服务器之间传输超文本数据(比如文字、图片、音频、视频等)的核心协议,当前互联网应用最广泛的版本是HTTP1.1,它基于经典的C/S模型,也就是客…...
