最近在工作中碰到一个问题,就是在Android P,设置-->声音中,通过拖动SeekBar设置音量,尤其是铃声音量时存在以下三个问题:1、滑动条不跟手,存在回弹的现象。2、偶发性的滑动条所在的位置与实际值不相符。3、偶发性的,滑动铃声音量条时,闹钟音量也跟着滑动。
对问题日志分析没有获得有价值的信息,通过查看代码发现,滑动条在Settings是一个叫VolumeSeekBarPreference的组件,其中铃声对应的控制器为RingVolumeSeekBarPreferenceController,仔细查看两者代码后发现,VolumeSeekBarPreference将绝大多数的关于SeekBar的操作都委托给了一个SeekBarVolumizer的对象,该对象位于framework/base/core/java/android.android.SeekBarVolumizer。
经过阅读发现,该对象实现了对SeekBar的监听,存储,更新等操作,并实现了预览音量效果的播放,但是没有实现停止播放,停止播放由SeekBarVolumizer的使用者通过其提供的回调接口及函数自行实现,Settings中是在SoundSettings中实现了该功能,通过实现了CallBack接口来实现相关功能,读者可自行查阅。
SeekBarVolumizer是一个涉及多个线程的类,将其功能性代码都注释掉后,发现SeekBar的滑动是正常的(当然所有功能也都失效了。。。),这可以说明上述问题确实是因为SeekBarVolumizer中的功能性代码引起的。
对代码按照其功能进行阅读分类,发现SeekBarVolumizer主要涉及3个线程,其中各个线程间通过Message或广播实现通信。
1、UI线程:该线程负责接受SeekBar的滑动事件,并将SeekBar的最新值更新到mLastProgress变量中,然后给mHandler发送一个消息MSG_SET_STREAM_VOLUME消息。UI线程还有一个mUiHandler,用于根据Message中携带的值来更新mLastProgress。
2、HandlerThread线程:该线程与mHandler绑定,当收到MSG_SET_STREAM_VOLUME消息时,将mLastProgress的值存储到AudioManager中。AudioManager在成功存值后,会发送一个VOLUME_CHANED广播,该广播携带了音量的类型(streamType)和音量值(streamValue)。
3、Receiver线程:顾名思义这是一个广播接收器(BroadcastReceiver),该广播接收器接收到AudioManager发出的广播后,从中取出音量的类型(streamType)和音量值(streamValue),使用其构建一个MSG_UPDATE_SLIDER消息,并将该消息发送给mUiHandler。
至此完成一个完整的循环,SeekBarV