SoundPool两类代码行为差异原因及stream未使用警告排查
问题背景
需求为触摸按钮时播放音频,手指抬起时停止。测试代码可正常实现长按循环播放、抬手停止的功能:
public boolean onTouch(View view, MotionEvent motionEvent) { switch (motionEvent.getAction()){ case MotionEvent.ACTION_DOWN: // -1 so it keeps looping fStream = soundPool.play(F4, 1, 1,0,-1,1); return true; case MotionEvent.ACTION_UP: soundPool.stop(fStream); } return false; }
实际项目添加条件后的代码如下:
全局变量定义:
int A4, A5, aStream; //global variable in MainActivity
触摸事件处理代码:
public boolean onTouch(View view, MotionEvent event) { switch (event.getAction()){ case MotionEvent.ACTION_DOWN: if(up){ horizontal_method(A5, A5_sharp, aStream); } else if(down){ horizontal_method(A4, A4_sharp, aStream); } return true; case MotionEvent.ACTION_UP: stop_audio_method(aStream); //soundPool.stop(aStream); } return false; }
辅助方法代码:
public void horizontal_method(int note, int sharp, int stream){ if(horizontal){ //if phone is moving loop_num = -1; } else { //if phone is not moving loop_num = 0; } rotate_method(note, sharp, stream, loop_num); } public void rotate_method(int note, int sharp, int stream, int loop_num){ if(rotate){ //if it's sharp stream = soundPool.play(sharp, 1, 1,0,loop_num,1); } else { // if it's normal note stream = soundPool.play(note, 1, 1,0,loop_num,1); } } public void stop_audio_method(int stream){ soundPool.stop(stream); }
遇到的问题
测试代码中音频可正常循环及停止,但项目代码中抬手后音频无法立即停止(循环时甚至永不停止),直接在ACTION_UP中调用soundPool.stop(aStream)也无效。同时rotate_method中的stream变量被提示“The value soundPool.play(...) assigned to stream is never used”,测试代码无此警告。
问题根源与解决方法
1. 核心问题:局部参数覆盖全局变量
你在rotate_method里给stream赋值,但这个stream是方法的局部参数,和全局的aStream完全是两个独立变量。也就是说,soundPool.play()返回的音频流ID根本没存到全局的aStream里,导致你在ACTION_UP时用的aStream还是初始默认值(0),自然无法停止正确的音频流。
测试代码里直接把返回值赋值给全局变量fStream,所以能正常停止;但项目代码里经过多层方法调用后,没有把返回的流ID更新到全局变量上。
2. 具体修改步骤
- 修改
rotate_method,让它返回音频流ID:
public int rotate_method(int note, int sharp, int loop_num){ if(rotate){ //if it's sharp return soundPool.play(sharp, 1, 1,0,loop_num,1); } else { // if it's normal note return soundPool.play(note, 1, 1,0,loop_num,1); } }
- 修改
horizontal_method,接收返回的流ID并继续返回:
public int horizontal_method(int note, int sharp){ int loop_num = horizontal ? -1 : 0; return rotate_method(note, sharp, loop_num); }
- 在触摸事件的
ACTION_DOWN中,将返回的流ID赋值给全局aStream:
case MotionEvent.ACTION_DOWN: if(up){ aStream = horizontal_method(A5, A5_sharp); } else if(down){ aStream = horizontal_method(A4, A4_sharp); } return true;
修改后,全局变量aStream就能正确存储当前播放的音频流ID,ACTION_UP时调用stop_audio_method(aStream)或者直接soundPool.stop(aStream)都能正常停止音频。
3. 关于变量未使用警告
之前rotate_method里的stream是局部参数,你给它赋值后既没有在方法内使用,也没有传递出去,所以IDE提示“赋值未使用”。改成返回值后,这个警告会自动消失,因为返回的流ID被上层方法接收并赋值给了全局变量。
内容的提问来源于stack exchange,提问作者motty_here

