ThinkChat🤖让你学习和工作更高效,注册即送10W Token,即刻开启你的AI之旅 广告
除了通过音量键可以调节音量以外,用户还可以在系统设置中进行调节。AudioManager.setStreamVolume()是系统设置界面中调整音量所使用的接口。 #### 1. setStreamVolume()分析 setStreamVolume()是SDK中提供给应用的API,它的作用是为特定的流类型设置范围内允许的任意音量。我们看一下它的实现: **AudioService.java-->AudioService.setStreamVolume()** ``` public void setStreamVolume(int streamType, intindex, int flags) { // 这里先判断一下流类型这个参数的有效性 ensureValidStreamType(streamType); // 获取保存了指定流类型音量信息的VolumeStreamState对象。 // 注意这里面使用mStreamVolumeAlias对这个数组进行了流类型的转换 VolumeStreamState streamState =mStreamStates[mStreamVolumeAlias[streamType]]; // 获取当前流将使用哪一个音频设备进行播放。它最终会调用到AudioPolicyService里去 final intdevice = getDeviceForStream(streamType); // 获取流当前的音量 final intoldIndex = streamState.getIndex(device, (streamState.muteCount()!= 0) /* lastAudible */); // 将原流类型下的音量值映射到目标流类型下的音量值 // 因为不同流类型的音量值刻度不一样,所以需要进行这个转换 index =rescaleIndex(index * 10, streamType, mStreamVolumeAlias[streamType]); //暂时先忽略下面这段if中的代码。它的作用根据flags的要求修改手机的情景模式 if(((flags & AudioManager.FLAG_ALLOW_RINGER_MODES) != 0) || (mStreamVolumeAlias[streamType] == getMasterStreamType())) { …… } // 调用setStreamVolumeInt() setStreamVolumeInt(mStreamVolumeAlias[streamType], index, device, false,true); // 获取设置的结果 index =mStreamStates[streamType].getIndex(device, (mStreamStates[streamType].muteCount() != 0) /*lastAudible */); // 广播通知 sendVolumeUpdate(streamType, oldIndex, index, flags); } ``` 看明白这个函数了吗?抛开被忽略掉的那个if块归纳一下:它的工作其实很简单的,就是执行下面这三方面的工作: - 为调用setStreamVolumeInt准备参数。 - 调用setStreamVolumeInt。 - 广播音量发生变化的通知。 分析的主线将转向setStreamVolumeInt()的内容了。 #### 2. setStreamVolumeInt()分析 看一下setStreamVolumeInt函数的代码,和往常一样,暂时忽略目前与分析目标无关的部分代码。 **AudioService.java-->AudioService.setStreamVolumeInt()** ``` private void setStreamVolumeInt(int streamType, int index, int device, boolean force, booleanlastAudible) { // 获取保存音量信息的VolumeStreamState对象 VolumeStreamState streamState = mStreamStates[streamType]; if(streamState.muteCount() != 0) { // 这里的内容是为了处理当流已经被静音后的情况。我们在讨论静音的实现时在考虑这段代码 …… } else { // 调用streamState.setIndex() if(streamState.setIndex(index, device, lastAudible) || force) { // 如果setIndex返回true或者force参数为true的话就在这里给mAudioHandler // sendMsg(mAudioHandler, MSG_SET_DEVICE_VOLUME, SENDMSG_QUEUE, device, 0, streamState, 0); } } } ``` 此函数有两个工作,一个是streamState.setIndex() 另一个则是根据setIndex()的返回值和force参数决定是否要发送MSG\_SET\_DEVICE\_VOLUME消息。这两个内容在3.2.1节中已经又介绍了。在此不再赘述。 其执行过程可以参考下面的序列图: :-: ![](http://img.blog.csdn.net/20150811133041805?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center) 图 3‑3setStreamVolume的处理流程 **注意** 看到这个序列图后,是否有读者感到眼熟呢?如果我们把setStreamVolumeInt()的内容替换掉在setStreamVolume()的对它的调用,再和adjustStreamVolume()函数进行以下比较,就会发现他们的内容出奇地相似。Android在其他地方也有这样的情况出现。从这一点上来说,已经发展到4.1版本的Android源码仍然尚不够精致。读者可以思考一下,有没有办法把这两个函数融合为一个函数呢? 到此,对于音量设置相关的内容就告一段落。接下来我们将讨论和音量相关的另一个重要的内容——静音。