Muting streams in Android

2019-04-29 21:52发布

I've built a small app that mutes/unmute the music stream using the class AudioManager. In fact, it works until I close the application. i.e. I've muted the sream, I close the app, I restart the app and the button doesn't unmute the stream any more. I've searched in the net but no one seems to have met this problem.

Here's my code:

public class ControlloVolume extends Activity {
ToggleButton tb_mute;
Button btn_mute;
AudioManager mAudioManager;
boolean mute;

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_controllo_volume);

    tb_mute = (ToggleButton) findViewById(R.id.tb_mute);
    btn_mute = (Button) findViewById(R.id.btn_mute);
    mAudioManager = (AudioManager)getSystemService(Context.AUDIO_SERVICE);

    if(mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC)==0){
        mute = true;
        tb_mute.setChecked(mute);
    }else{
        mute = false;
        tb_mute.setChecked(mute);
    }

    }

public void onButtonClicked(View view){
    if(!mute){
        mAudioManager.setStreamMute(AudioManager.STREAM_MUSIC, true);
        tb_mute.setChecked(true);
        mute = true;
    }else{
        mAudioManager.setStreamMute(AudioManager.STREAM_MUSIC, false);
        tb_mute.setChecked(false);
        mute = false;
    }
}

1条回答
做个烂人
2楼-- · 2019-04-29 22:18

First, beware it's not recommended

For a better user experience, applications MUST unmute a muted stream in onPause() and mute it again in onResume() if appropriate.

But I assume you know what you're doing, so here we go.

Note this line from the docs on setStreamMute

The mute command is protected against client process death: if a process with an active mute request on a stream dies, this stream will be unmuted automatically.

I've checked on my device and indeed, when I just exit my activity, stream stays muted. But as soon as I kill the process, mute goes away. Take a look at activity lifecycle.

As your current approach will not work reliably, you could write a foreground service which will trigger the mute - start that service from your activity. Also you would likely need to setStreamSolo.

Two important things.

  1. Volume==0 and muted are NOT the same thing. I.e. stream can have volume==0 but be not muted. Though if stream is muted, volume will always be 0
  2. mute requests are cumulative. I.e. if you've set mute twice, you must unmute twice as well - your code doesn't handle that

As a side note, for such app you would probably want to use widget instead of activity.


Off topic. It seems surprisingly lot of people don't quite get how booleans work. And as I see code such as yours regulary, here is a bit streamlined rewrite.

@Override
public void onCreate(Bundle savedInstanceState) {
    // ... setup just like you did

    // boolean is just like any other type. You can assign not only
    // constants, but expressions too
    mute = (mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC)==0);
    tb_mute.setChecked(mute);
}

public void onButtonClicked(View view){
    mute = !mute; // invert value
    mAudioManager.setStreamMute(AudioManager.STREAM_MUSIC, mute);
    tb_mute.setChecked(mute);
}
查看更多
登录 后发表回答