安卓基础:多媒体、图片、音视频、摄像头、传感器
编程">多媒体编程
图片处理
加载大图片
Android 模拟器默认为每个应用分配的堆内存空间是16M 当加载大图片时,加载图片需要的内存空间不是按图片的大小来算的,而是按像素点的多少来算的 图片加载到内存中需要把每一个像素都加载到内存中,容易造成OOM(OutOfMemoryError) 内存溢出致命错误采用缩放方式加载图片
public void click(View v) { //创建一个位图工厂的配置参数 BitmapFactory.Options options = new Options(); //解码器不去真正的解析位图 但是还能够获取图片的宽和高信息 options.inJustDecodeBounds = true; BitmapFactory.decodeFile("/mnt/sdcard/dog.jpg",options); //[2]获取图片的宽和高信息 int imgWidth = options.outWidth; int imgHeight = options.outHeight; System.out.println("图片的宽和高:"+imgWidth+"----"+imgHeight); //[3]计算缩放缩放比 int scale = 1; int scaleX = imgWidth/width; int scaleY = imgHeight/height; if (scaleX>=scaleY && scaleX>scale) { scale = scaleX; } if (scaleY > scaleX && scaleY>scale) { scale = scaleY; } System.out.println("缩放比==:"+scale); //[4]安装缩放比进行显示 生物学 丁磊 options.inSampleSize = scale; //[5]安装缩放比 进行解析位图 options.inJustDecodeBounds = false; Bitmap bitmap = BitmapFactory.decodeFile("/mnt/sdcard/dog.jpg",options); //[6]把bitmap显示iv上 iv.setImageBitmap(bitmap); }
创建一个原图的副本
public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //显示原图 ImageView iv_src = (ImageView) findViewById(R.id.iv_src); //显示副本 ImageView iv_copy = (ImageView) findViewById(R.id.iv_copy); //[1]先把tomcat.png 图片转换成bitmap 显示到iv_src Bitmap srcBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.tomcat); //[1.1]操作图片 // srcBitmap.setPixel(20, 30, Color.RED); iv_src.setImageBitmap(srcBitmap); //[2]创建原图的副本 //[2.1]创建一个模板 相当于 创建了一个大小和原图一样的 空白的白纸 Bitmap copybiBitmap = Bitmap.createBitmap(srcBitmap.getWidth(), srcBitmap.getHeight(), srcBitmap.getConfig()); //[2.2]想作画需要一个画笔 Paint paint = new Paint(); //[2.3]创建一个画布 把白纸铺到画布上 Canvas canvas = new Canvas(copybiBitmap); //[2.4]开始作画 canvas.drawBitmap(srcBitmap, new Matrix(), paint); //[2.5]操作画出来的小猫图片 for (int i = 0; i < 20; i++) { copybiBitmap.setPixel(20+i, 30, Color.RED); } //[3]把copybimap显示到iv_copy上 iv_copy.setImageBitmap(copybiBitmap); } }
图片操作API
图片的特效包括,图形的缩放、镜面、倒影、旋转、位移等。图片的特效是将原图的图形矩阵乘以一个特效矩阵,形成一个新的图形矩阵来实现 Matrix 维护了一个3*3 的矩阵去更改像素点的坐标旋转,缩放,平移,镜面,倒影
public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //显示原图 ImageView iv_src = (ImageView) findViewById(R.id.iv_src); //显示副本 ImageView iv_copy = (ImageView) findViewById(R.id.iv_copy); //[1]先把tomcat.png 图片转换成bitmap 显示到iv_src Bitmap srcBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.tomcat); //[1.1]操作图片 // srcBitmap.setPixel(20, 30, Color.RED); iv_src.setImageBitmap(srcBitmap); //[2]创建原图的副本 //[2.1]创建一个模板 相当于 创建了一个大小和原图一样的 空白的白纸 Bitmap copybiBitmap = Bitmap.createBitmap(srcBitmap.getWidth(), srcBitmap.getHeight(), srcBitmap.getConfig()); //[2.2]想作画需要一个画笔 Paint paint = new Paint(); //[2.3]创建一个画布 把白纸铺到画布上 Canvas canvas = new Canvas(copybiBitmap); //[2.4]开始作画 Matrix matrix = new Matrix(); //[2.5]对图片进行旋转 //matrix.setRotate(20, srcBitmap.getWidth()/2, srcBitmap.getHeight()/2); //[2.5]对图片进行缩放 // matrix.setScale(0.5f, 0.5f); //[2.6]对图片进行平移 // matrix.setTranslate(30, 0); //[2.7]镜面效果 如果2个方法一起用 // matrix.setScale(-1.0f, 1); //post是在上一次修改的基础上进行再次修改 set 每次操作都是最新的 会覆盖上次的操作 // matrix.postTranslate(srcBitmap.getWidth(), 0); //[2,7]倒影效果 matrix.setScale(1.0f, -1); //post是在上一次修改的基础上进行再次修改 set 每次操作都是最新的 会覆盖上次的操作 matrix.postTranslate(0, srcBitmap.getHeight()); canvas.drawBitmap(srcBitmap,matrix , paint); //[3]把copybimap显示到iv_copy上 iv_copy.setImageBitmap(copybiBitmap); } }
模拟画图功能
原理:
Android 中只有View 才可以捕获到用户触摸的事件
ImageView 控件可以设置一个触摸事件的监听器来监听触摸事件,重写OnTouchListener 的onTouch 方法,结合Canvas 类,即可实现随手涂鸦的画板功能
TIPS:
onTouch 方法的返回值默认是false 的,必须设置为true,否则触摸事件将不会被处理
触摸事件:
MotionEvent.ACTION_DOWN 按下
MotionEvent.ACTION_MOVE 移动
MotionEvent.ACTION_UP 抬起
代码
public class MainActivity extends Activity { private Bitmap srcBitmap; private ImageView iv; private Bitmap copyBitmap; private Paint paint; private Canvas canvas; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // 用来显示我们画的内容 iv = (ImageView) findViewById(R.id.iv); // [1]获取原图 bg srcBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.bg); // [2]获取原图的副本 相当于是一个空白 的白纸 copyBitmap = Bitmap.createBitmap(srcBitmap.getWidth(), srcBitmap.getHeight(), srcBitmap.getConfig()); // 创建画笔 paint = new Paint(); // 创建一个画布 canvas = new Canvas(copyBitmap); // 开始作画 canvas.drawBitmap(srcBitmap, new Matrix(), paint); // canvas.drawLine(20, 30, 50, 80, paint); iv.setImageBitmap(copyBitmap); // [3]给iv设置一个触摸事件 iv.setOnTouchListener(new OnTouchListener() { int startX = 0; int startY = 0; @Override public boolean onTouch(View v, MotionEvent event) { // 获取当前事件类型 int action = event.getAction(); switch (action) { case MotionEvent.ACTION_DOWN: // 按下 System.out.println("摸view"); // 获取开始位置 (划线) startX = (int) event.getX(); startY = (int) event.getY(); break; case MotionEvent.ACTION_MOVE:// 移动 System.out.println("移动"); // 获取结束位置 int stopX = (int) event.getX(); int stopY = (int) event.getY(); // [不停的画线] canvas.drawLine(startX, startY, stopX, stopY, paint); // 在次显示到iv上 iv.setImageBitmap(copyBitmap); // 更新一下开始坐标和结束坐标 startX = stopX; startY = stopY; break; case MotionEvent.ACTION_UP:// 抬起 System.out.println("抬起"); break; } // True if the listener has consumed the event, false otherwise return true; // true 监听器处理完事件了 } }); } // 点击按钮 改变画笔的颜色 public void click1(View v) { paint.setColor(Color.RED); } // 点击按钮 对画笔加粗 public void click2(View v) { paint.setStrokeWidth(15); } // 点击按钮 对画笔加粗 public void click3(View v) { /** * format 保存图片的格式 * quality 保存图片的质量 * SystemClock.uptimeMillis() 这个是当前手机的开机时间 */ try { File file = new File(Environment.getExternalStorageDirectory().getPath(),SystemClock.uptimeMillis()+".png"); FileOutputStream fos = new FileOutputStream(file); copyBitmap.compress(CompressFormat.PNG, 100, fos); //发送一条广播 欺骗系统图库的应用 Intent intent = new Intent(); //设置action intent.setAction(Intent.ACTION_MEDIA_MOUNTED); intent.setData(Uri.fromFile(Environment.getExternalStorageDirectory())); //发送一条广播 sendBroadcast(intent); } catch (Exception e) { e.printStackTrace(); } } }
撕衣服案例
原理:
一张图片有衣服,一张图片没有衣服。
没有衣服的图片放置在下面,有衣服的图片放置在上面,
为在上面的ImageView 设置触摸的事件,
当手指触摸到图片上时,将手指触摸的点周边的上层图片的像素点设置为透明的,就会出现一个撕衣服的效果。
代码
public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //用来显示 操作后的图片 final ImageView iv = (ImageView) findViewById(R.id.iv); //[1]获取要操作图片 原图 Bitmap srcBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.pre19); //[2]创建一个副本 相当于有一个和原图大小的白纸 final Bitmap alterBitmap = Bitmap.createBitmap(srcBitmap.getWidth(), srcBitmap.getHeight(), srcBitmap.getConfig()); //创建画笔 Paint paint = new Paint(); //创建画布 把白纸铺到画布上 Canvas canvas = new Canvas(alterBitmap); //开始作画 canvas.drawBitmap(srcBitmap, new Matrix(), paint); iv.setImageBitmap(alterBitmap); //[3]给vi设置一个触摸事件 iv.setOnTouchListener(new OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { //[4]具体判断一下触摸事件 switch (event.getAction()) { case MotionEvent.ACTION_MOVE://移动事件 for (int i = -7; i < 7; i++) { //增加X轴坐标 for (int j = -7; j < 7; j++) { //增加Y轴坐标 //为了良好的用户体验 撕一个圆 if (Math.sqrt(i*i+j*j)<7) { try { alterBitmap.setPixel((int)event.getX()+i, (int)event.getY()+j, Color.TRANSPARENT); } catch (Exception e) { } } } } //更新一下iv iv.setImageBitmap(alterBitmap); break; } return true; } }); } }
音频播放
MediaPlayer
流程图
该播放器同时只能播放一个音乐文件,文件大小并没有限制
SoundPool
SoundPool 和其他声音播放类相比,其特点是可以自行设置声音的品质、音量、播放比率等参数。并且它可以同时管理多个音频流,每个流都有独自的ID,对某个音频流的管理都是通过ID 进行的。
应用场景
程序中有些很短小音频需要经常播放,例如:游戏音效 如果使用MediaPlayer 每次加载音频、播放、再释放,这样很费事 我们可以使用音频池一次性加载多个音频,需要哪个就直接播放 SoundPool 最大只能申请1M 的内存空间,这就意味着我们只能用一些很短的声音片段 SoundPool 提供了pause 和stop 方法,把缓冲区里的数据播放完才会停下来,也许会多播放一秒钟使用步骤
创建SoundPool 实例, 第一个参数用于指定最大可以加载声音个数 SoundPool soundPool=new SoundPool(3,AudioManager.STREAM_MUSIC, 0); 加载不同的声音文件,生成各自的声音id int shoot1ID = soundPool.load(this, R.raw.shoot1, 1); int shoot2ID = soundPool.load(this, R.raw.shoot2, 1); int shoot3ID = soundPool.load(this, R.raw.shoot3, 1); 根据load 方法获取的id 播放对应的声音 soundPool.play(shoot1ID, 1, 1, 1, 0, 1); soundPool.play(shoot2ID, 1, 1, 1, 0, 1); soundPool.play(shoot3ID, 1, 1, 1, 0, 1);
模拟实现音频播放器
TIPS:
播放网络音乐应使用异步播放,设置一个准备完成的监听
public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } //点击按钮 播放一个音频文件 public void click(View v) { //[1]初始化mediaplayer final MediaPlayer mediaPlayer = new MediaPlayer(); //[2]设置要播放的资源位置 path 可以是网络 路径 也可是本地路径 try { mediaPlayer.setDataSource("https://192.168.11.86:8080/xpg.mp3"); //[3]准备播放 mediaPlayer.prepareAsync(); //[3.1]设置一个准备完成的监听 mediaPlayer.setOnPreparedListener(new OnPreparedListener() { @Override public void onPrepared(MediaPlayer mp) { //[4]开始播放 mediaPlayer.start(); } }); } catch (Exception e) { e.printStackTrace(); } } }
模拟播放器代码
public class MainActivity extends Activity implements OnSeekBarChangeListener { private EditText et_path; private SeekBar sb; private TextView tv_time; private MediaPlayer player; private int duration; private boolean isUpdateBar; // 播放器的几个状态 private static final int PLAYING = 1;// 播放状态 private static final int PAUSING = 2;// 暂停状态 private static final int STOPPING = 3;// 停止状态 private int CURRENT = 0;// 当前状态 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // 初始化界面控件 et_path = (EditText) findViewById(R.id.et_path); sb = (SeekBar) findViewById(R.id.sb); // 给SeekBar 绑定滑动事件 sb.setOnSeekBarChangeListener(this); tv_time = (TextView) findViewById(R.id.tv_time); } // 播放音乐 public void play(View view) { if (player != null) { if (CURRENT == PLAYING) { return; } else if (CURRENT == PAUSING) { player.start(); CURRENT = PLAYING; updateSeekBar(); return; } else if (CURRENT == STOPPING) { player.reset(); player.release(); } } try { // 创建一个播放器对象 player = new MediaPlayer(); // 获取音乐路径 String path = et_path.getText().toString(); // 给播放器设置音乐路径 player.setDataSource(path); // 设置音乐格式 player.setAudioStreamType(AudioManager.STREAM_MUSIC); // 准备 player.prepare(); // 获取音乐最大长度(毫秒单位) duration = player.getDuration(); // 给SeekBar 设置最大值 sb.setMax(duration); // 格式化输出音乐长度 String lastString = formatTime(duration); tv_time.setText("00:00/" + lastString); // 音乐开始播放 player.start(); // 更新SeekBar updateSeekBar(); } catch (Exception e) { e.printStackTrace(); Toast.makeText(this, "音乐播放失败" + e, 0).show(); } } // 暂停 public void pause(View view) { if (player != null && CURRENT == PLAYING) { player.pause(); stopSeekBar(); CURRENT = PAUSING; } } // 停止播放 public void stop(View view) { if (player != null) { if (CURRENT == PLAYING || CURRENT == PAUSING) { player.stop(); stopSeekBar(); sb.setProgress(0); tv_time.setText("00:00/" + formatTime(duration)); CURRENT = STOPPING; } } } // 重新播放 public void replay(View view) { if (player != null) { stopSeekBar(); CURRENT = STOPPING; play(view); } } // 停止SeekBar 更新 private void stopSeekBar() { isUpdateBar = false; } // 更新SeekBar private void updateSeekBar() { isUpdateBar = true; new Thread(new Runnable() { @Override public void run() { while (isUpdateBar) { // 每秒更新一次 SystemClock.sleep(1000); if (player != null && CURRENT == PLAYING) { sb.setProgress(player.getCurrentPosition()); // 在主线程中运行如下代码更新EditText runOnUiThread(new Runnable() { @Override public void run() { String current = formatTime(player .getCurrentPosition()); String durationString = formatTime(duration); tv_time.setText(current + "/" + durationString); } }); } } } }).start(); } @Override public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { if (player != null) { player.seekTo(progress); } } // 开始拖动SeekBar 时停止更新SeekBar public void onStartTrackingTouch(SeekBar seekBar) { stopSeekBar(); } // 停止拖动SeekBar 的时候将音乐定位到相应位置 public void onStopTrackingTouch(SeekBar seekBar) { if (player != null) { player.seekTo(seekBar.getProgress()); updateSeekBar(); } } // 工具函数格式化播放时间 private String formatTime(int current) { int second = current / 1000; int minute = second / 60; second = second - minute * 60; StringBuilder sb = new StringBuilder(); sb.append(minute > 10 ? minute + "" : "0" + minute); sb.append(":"); sb.append(second > 10 ? second : "0" + second); return sb.toString(); } }
视频播放
使用MediaPlayer+SurfaceView 播放视频
代码
public class MainActivity extends Activity { private MediaPlayer mediaPlayer; private int currentPosition; //当前视频播放的位置 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //[0]找到控件用来显示播放视频的内容 final SurfaceView sfv = (SurfaceView) findViewById(R.id.sfv); //获取holder 对象 用来维护视频播放的内容 SurfaceHolder holder = sfv.getHolder(); //[0.1]添加holder 生命周期 方法 holder.addCallback(new Callback() { //当surface view 销毁 @Override public void surfaceDestroyed(SurfaceHolder holder) { System.out.println("surfaceDestroyed"); //停止播放视频 if (mediaPlayer!=null && mediaPlayer.isPlaying()) { //获取到当前播放视频的位置 currentPosition = mediaPlayer.getCurrentPosition(); mediaPlayer.stop(); } } //这个方法执行了 说明sufaceView准备好了 @Override public void surfaceCreated(SurfaceHolder holder) { //[1]初始化mediaplayer System.out.println("surfaceCreated"); mediaPlayer = new MediaPlayer(); //[2]设置要播放的资源位置 path 可以是网络 路径 也可是本地路径 try { mediaPlayer.setDataSource("https://192.168.11.86:8080/cc.MP4"); //[3]准备播放 mediaPlayer.prepareAsync(); //[3.0]设置显示给sfv sufraceholder 是用来维护视频播放的内容 mediaPlayer.setDisplay(holder); //[3.1]设置一个准备完成的监听 mediaPlayer.setOnPreparedListener(new OnPreparedListener() { @Override public void onPrepared(MediaPlayer mp) { //[4]开始播放 mediaPlayer.start(); //[5]继续上次的位置继续播放 mediaPlayer.seekTo(currentPosition); } }); } catch (Exception e) { e.printStackTrace(); } } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { } }); } }
使用vitamio控件播放
控件清单文件初始化配置
使用全命名的标签
代码
public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // 插件vitamio框架检查是否可用 if (!LibsChecker.checkVitamioLibs(this)) { return; } final VideoView vv = (VideoView) findViewById(R.id.vv); vv.setVideoPath("https://192.168.11.86:8080/aa.avi"); vv.setOnPreparedListener(new OnPreparedListener() { @Override public void onPrepared(MediaPlayer mp) { vv.start(); } }); //设置video的控制器 vv.setMediaController(new MediaController(this)); } }
摄像头
调用系统摄像头进行拍照和摄像,只需知道系统摄像头的action 和category 就可以调用系统摄像头。
Camera 类的action 和category
VideoCamera 类的action 和category
TIPS
由于希望在调用拍照或摄像功能后回到当前应用的界面,且得知拍照或摄像的结果如何,是否成功,所以在开启Activity 时不能使用startActivity 方法,而是使用startActivityForResult 方法开启Activity,并重写onActivityResult方法处理回传的数据。
代码示例
public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } //点击按钮进行照相 public void click1(View v){ Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); File file = new File(Environment.getExternalStorageDirectory().getPath(),"haha.png"); intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(file)); // 保存图片的位置 // start the image capture Intent startActivityForResult(intent, 1); } //点击按钮进行录像 public void click2(View v){ Intent intent = new Intent(MediaStore.ACTION_VIDEO_CAPTURE); File file = new File(Environment.getExternalStorageDirectory().getPath(),"heheh.MP4"); intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(file)); // 保存图片的位置 // start the image capture Intent startActivityForResult(intent, 2); } //当开启的Activity关闭的时候调用 @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { System.out.println("哈哈哈"); super.onActivityResult(requestCode, resultCode, data); } }
传感器
Android 手机中内置了很多传感器,其主要类型有:方向、加速度(重力)、光线、磁场、距离(临近性)、温度等
方向传感器Sensor.TYPE_ORIENTATION 加速度(重力)传感器Sensor.TYPE_ACCELEROMETER 光线传感器Sensor.TYPE_LIGHT 磁场传感器Sensor.TYPE_MAGNETIC_FIELD 距离(临近性)传感器Sensor.TYPE_PROXIMITY 温度传感器Sensor.TYPE_TEMPERATURE获取传感器管理器SensorManager:SensorManager sm = (SensorManager) getSystemService(SENSOR_SERVICE);
通过传感器管理器对象获得指定类型的传感器Sensor sensor = sm.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
通过传感器管理器对象获得手机中所有的传感器:
//获取手机支持的所有传感器 List sensorList = sm.getSensorList(Sensor.TYPE_ALL); for (int i = 0; i < sensorList.size(); i++) { Sensor sensor = sensorList.get(i); // 获取传感器名称 String name = sensor.getName(); // 获取传感器厂商 String vendor = sensor.getVendor(); // 获取传感器版本号 int version = sensor.getVersion(); }
使用传感器管理器对象注册传感器来使一个传感器工作
/* * 注册一个传感器 第二个参数Sensor 是具体某个传感器对象 第三个参数是设定传感器采样频率 */ sm.registerListener(new SensorEventListener() { // 当传感器值改变时触发该函数 @Override public void onSensorChanged(SensorEvent event) { Toast.makeText(MainActivity.this, "" + event.accuracy, 0) .show(); } // 当传感器精确度更改是触发该函数 @Override public void onAccuracyChanged(Sensor sensor, int accuracy) { Toast.makeText(MainActivity.this, "" + accuracy, 1).show(); } }, sensor, SensorManager.SENSOR_DELAY_NORMAL);
listener :传感器事件监听器 sensor :要被注册的传感器对象 rate :采样率,分为最快、游戏、普通、用户界面几种当应用程序请求特定的采样率时,其实只是对传感器子系统的一个建议,不保证特定的采样率可用。
采样率的四种类型详解:
最快: SensorManager.SENSOR_DELAY_FASTEST
最低延迟,一般不是特别敏感的处理不推荐使用,该种模式可能造成手机电力大量消耗,由于传递的为原始数据,算法不处理好将会影响游戏逻辑和UI 的性能
游戏: SensorManager.SENSOR_DELAY_GAME
游戏延迟,一般绝大多数的实时性较高的游戏都使用该级别
普通: SensorManager.SENSOR_DELAY_NORMAL
标准延迟,对于一般的益智类或EASY 级别的游戏可以使用,但过低的采样率可能对一些赛车类游戏有跳帧现象
用户界面: SensorManager.SENSOR_DELAY_UI
一般对于屏幕方向自动旋转使用,相对节省电能和逻辑处理,一般游戏开发中我们不使用
案例手机防盗
案例手机防盗
当手机从衣服兜里被掏出时,手机响铃报警
原理:
使用距离传感器,当距离从0 变为1 时,使用MediaPlayer 播放声音文件报警
继承SensorEventListener 并覆写抽象方法
public void onSensorChanged(SensorEvent event) { // 获取距离传感器的值 float value = event.values[0]; if (value > 0) { try { // 如果距离大于0 则播放音乐 player.start(); } catch (Exception e) { e.printStackTrace(); } } else { // 如果距离等于0 暂停音乐 player.pause(); } }