音量变化是否有播放动作?
我正在编程一个小部件,每当用户更改铃声音量或振动设置时都需要更新。
捕获android.media.VIBRATE_SETTING_CHANGED
对于振动设置工作得很好,但是我还没有find任何方式在振铃音量发生变化时得到通知,尽pipe当用户按下音量增大/减小的物理键时我可以尝试捕获,还有许多其他的选项可以在不使用这些键的情况下改变音量。
你知道是否有任何广播行动或任何方式来创build一个或没有它的解决问题?
没有广播动作,但我确实发现你可以连接一个内容观察者,当设置改变时得到通知,stream的音量就是其中一些设置。 注册android.provider.Settings.System.CONTENT_URI以通知所有设置更改:
mSettingsContentObserver = new SettingsContentObserver( new Handler() ); this.getApplicationContext().getContentResolver().registerContentObserver( android.provider.Settings.System.CONTENT_URI, true, mSettingsContentObserver );
内容观察者可能看起来像这样:
public class SettingsContentObserver extends ContentObserver { public SettingsContentObserver(Handler handler) { super(handler); } @Override public boolean deliverSelfNotifications() { return super.deliverSelfNotifications(); } @Override public void onChange(boolean selfChange) { super.onChange(selfChange); Log.v(LOG_TAG, "Settings change detected"); updateStuff(); } }
一定要注销内容观察者。
内森的代码工作,但给每个更改系统设置两个通知。 为避免这种情况,请使用以下内容
public class SettingsContentObserver extends ContentObserver { int previousVolume; Context context; public SettingsContentObserver(Context c, Handler handler) { super(handler); context=c; AudioManager audio = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); previousVolume = audio.getStreamVolume(AudioManager.STREAM_MUSIC); } @Override public boolean deliverSelfNotifications() { return super.deliverSelfNotifications(); } @Override public void onChange(boolean selfChange) { super.onChange(selfChange); AudioManager audio = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); int currentVolume = audio.getStreamVolume(AudioManager.STREAM_MUSIC); int delta=previousVolume-currentVolume; if(delta>0) { Logger.d("Decreased"); previousVolume=currentVolume; } else if(delta<0) { Logger.d("Increased"); previousVolume=currentVolume; } } }
然后在你的服务onCreate注册它:
mSettingsContentObserver = new SettingsContentObserver(this,new Handler()); getApplicationContext().getContentResolver().registerContentObserver(android.provider.Settings.System.CONTENT_URI, true, mSettingsContentObserver );
然后在onDestroy中取消注册:
getApplicationContext().getContentResolver().unregisterContentObserver(mSettingsContentObserver);
是的,你可以注册一个音量变化的接收器(这是一种黑客,但工程),我设法这样做(不涉及ContentObserver):在清单xml文件中:
<receiver android:name="com.example.myproject.receivers.MyReceiver" > <intent-filter> <action android:name="android.media.VOLUME_CHANGED_ACTION" /> </intent-filter> </receiver>
广播接收器:
public class MyReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { if (intent.getAction().equals("android.media.VOLUME_CHANGED_ACTION")) { Log.d("Music Stream", "has changed"); } } }
希望它有帮助!
内森和阿迪的代码是有效的,但是可以清理和自我包含:
public class AudioStreamVolumeObserver { public interface OnAudioStreamVolumeChangedListener { void onAudioStreamVolumeChanged(int audioStreamType, int volume); } private static class AudioStreamVolumeContentObserver extends ContentObserver { private final AudioManager mAudioManager; private final int mAudioStreamType; private final OnAudioStreamVolumeChangedListener mListener; private int mLastVolume; public AudioStreamVolumeContentObserver( @NonNull Handler handler, @NonNull AudioManager audioManager, int audioStreamType, @NonNull OnAudioStreamVolumeChangedListener listener) { super(handler); mAudioManager = audioManager; mAudioStreamType = audioStreamType; mListener = listener; mLastVolume = mAudioManager.getStreamVolume(mAudioStreamType); } @Override public void onChange(boolean selfChange) { int currentVolume = mAudioManager.getStreamVolume(mAudioStreamType); if (currentVolume != mLastVolume) { mLastVolume = currentVolume; mListener.onAudioStreamVolumeChanged(mAudioStreamType, currentVolume); } } } private final Context mContext; private AudioStreamVolumeContentObserver mAudioStreamVolumeContentObserver; public AudioStreamVolumeObserver( @NonNull Context context) { mContext = context; } public void start(int audioStreamType, @NonNull OnAudioStreamVolumeChangedListener listener) { stop(); Handler handler = new Handler(); AudioManager audioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE); mAudioStreamVolumeContentObserver = new AudioStreamVolumeContentObserver(handler, audioManager, audioStreamType, listener); mContext.getContentResolver() .registerContentObserver(System.CONTENT_URI, true, mAudioStreamVolumeContentObserver); } public void stop() { if (mAudioStreamVolumeContentObserver == null) { return; } mContext.getContentResolver() .unregisterContentObserver(mAudioStreamVolumeContentObserver); mAudioStreamVolumeContentObserver = null; } }
基于纳森的 adi和swooby的代码,我创build了一个完整的工作示例,并进行了一些小改进。
outlookAudioFragment
类,我们可以看到使用我们的自定义ContentObserver
监听音量变化是多么容易。
public class AudioFragment extends Fragment implements OnAudioVolumeChangedListener { private AudioVolumeObserver mAudioVolumeObserver; @Override public void onResume() { super.onResume(); // initialize audio observer if (mAudioVolumeObserver == null) { mAudioVolumeObserver = new AudioVolumeObserver(getActivity()); } /* * register audio observer to identify the volume changes * of audio streams for music playback. * * It is also possible to listen for changes in other audio stream types: * STREAM_RING: phone ring, STREAM_ALARM: alarms, STREAM_SYSTEM: system sounds, etc. */ mAudioVolumeObserver.register(AudioManager.STREAM_MUSIC, this); } @Override public void onPause() { super.onPause(); // release audio observer if (mAudioVolumeObserver != null) { mAudioVolumeObserver.unregister(); } } @Override public void onAudioVolumeChanged(int currentVolume, int maxVolume) { Log.d("Audio", "Volume: " + currentVolume + "/" + maxVolume); Log.d("Audio", "Volume: " + (int) ((float) currentVolume / maxVolume) * 100 + "%"); } }
public class AudioVolumeContentObserver extends ContentObserver { private final OnAudioVolumeChangedListener mListener; private final AudioManager mAudioManager; private final int mAudioStreamType; private int mLastVolume; public AudioVolumeContentObserver( @NonNull Handler handler, @NonNull AudioManager audioManager, int audioStreamType, @NonNull OnAudioVolumeChangedListener listener) { super(handler); mAudioManager = audioManager; mAudioStreamType = audioStreamType; mListener = listener; mLastVolume = audioManager.getStreamVolume(mAudioStreamType); } /** * Depending on the handler this method may be executed on the UI thread */ @Override public void onChange(boolean selfChange, Uri uri) { if (mAudioManager != null && mListener != null) { int maxVolume = mAudioManager.getStreamMaxVolume(mAudioStreamType); int currentVolume = mAudioManager.getStreamVolume(mAudioStreamType); if (currentVolume != mLastVolume) { mLastVolume = currentVolume; mListener.onAudioVolumeChanged(currentVolume, maxVolume); } } } @Override public boolean deliverSelfNotifications() { return super.deliverSelfNotifications(); } }
public class AudioVolumeObserver { private final Context mContext; private final AudioManager mAudioManager; private AudioVolumeContentObserver mAudioVolumeContentObserver; public AudioVolumeObserver(@NonNull Context context) { mContext = context; mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); } public void register(int audioStreamType, @NonNull OnAudioVolumeChangedListener listener) { Handler handler = new Handler(); // with this handler AudioVolumeContentObserver#onChange() // will be executed in the main thread // To execute in another thread you can use a Looper // +info: https://stackoverflow.com/a/35261443/904907 mAudioVolumeContentObserver = new AudioVolumeContentObserver( handler, mAudioManager, audioStreamType, listener); mContext.getContentResolver().registerContentObserver( android.provider.Settings.System.CONTENT_URI, true, mAudioVolumeContentObserver); } public void unregister() { if (mAudioVolumeContentObserver != null) { mContext.getContentResolver().unregisterContentObserver(mAudioVolumeContentObserver); mAudioVolumeContentObserver = null; } } }
public interface OnAudioVolumeChangedListener { void onAudioVolumeChanged(int currentVolume, int maxVolume); }
希望它对于某人仍然有用! 🙂
嗨,我试过上面的代码,它不适合我。 但是当我试图添加这一行
getActivity().setVolumeControlStream(AudioManager.STREAM_MUSIC);
并放
mSettingsContentObserver = new SettingsContentObserver(this,new Handler()); getApplicationContext().getContentResolver().registerContentObserver(android.provider.Settings.System.CONTENT_URI, true, mSettingsContentObserver );
它现在有效。 我关心的是如何隐藏音量对话框onchange。 看到这个图像 。
如果其唯一的振铃模式更改,您可以使用Brodcast接收器“ android.media.RINGER_MODE_CHANGED
”作为动作。 这将很容易实施