<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ThinkChat2.0新版上線,更智能更精彩,支持會話、畫圖、視頻、閱讀、搜索等,送10W Token,即刻開啟你的AI之旅 廣告
                靜音控制的情況與音量調節又很大的不同。因為每個應用都有可能進行靜音操作,所以為了防止狀態發生紊亂,就需要為靜音操作進行計數,也就是說多次靜音后需要多次取消靜音才可以。 不過,如果進行了靜音計數后還會引入另外一個問題。如果一個應用在靜音操作(計數加1)后因為某種原因不小心掛了,那么將不會有人再為它進行取消靜音的操作,靜音計數無法再回到0,也就是說這個倒霉的流將被永遠靜音下去。 那么怎么處理應用異常退出后的靜音計數呢?AudioService的解決辦法是記錄下來每個應用的自己的靜音計數,當應用崩潰時,在總的靜音計數中減去崩潰應用自己的靜音計數,也就是說,由我們為這個應用完成它沒能完成的取消靜音這個操作。為此,VolumeStreamState定義了一個繼承自DeathRecepient的內部類名為VolumeDeathHandler,并為每個進行靜音操作的進程創建一個實例。它保存了對應進程的靜音計數,并在進程死亡時進行計數清零的操作。從這個名字來看可能是Google希望這個類將來能夠承擔更多與音量相關的事情吧,不過眼下它只負責靜音。我們將在后續的內容對這個類進行深入的講解。 經過前面的介紹,我們不難得出AudioService、VolumeStreamState與VolumeDeathHandler的關系如下: :-: ![](http://img.blog.csdn.net/20150811133130548?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center) 圖 3-4 與靜音相關的類 #### 1. setStreamMute()分析 同音量設置一樣,靜音控制也是相對于某一個流類型而言的。而且正如本節開頭所提到的,靜音控制涉及到引用計數和客戶端進程的死亡監控。所以相對與音量控制來說,靜音控制有一定的復雜度。不過還好,靜音控制對外入口只有一個函數,就是AudioManager.setStreamMute()。第二個參數state為true表示靜音,否則為解除靜音。 **AudioManager.java-->AudioManager.setStreamMute()** ``` public void setStreamMute(int streamType, booleanstate) { IAudioService service = getService(); try { // 調用AudioService的setStreamMute,注意第三個參數mICallBack。 service.setStreamMute(streamType, state, mICallBack); } catch(RemoteException e) { Log.e(TAG, "Dead object in setStreamMute", e); } } ``` AudioManager一如既往地充當著一個AudioService代理的一個角色。但是這次有一個小小的卻很重要的動作。AudioManager給AudioService傳入了一個名為mICallBack的變量。查看一下它的定義: private final IBinder mICallBack = new Binder(); 真是簡單得不得了。全文搜索一下,我們發現它只被用來作為AudioService的幾個函數調用的參數。從AudioManager這邊看來它沒有任何實際意義。其實,這在Android中進程間交互通訊中是一種常見且非常重要的技術。mICallBack這個簡單的變量可以充當Bp端在Bn端的一個唯一標識。Bn端,也就是AudioService拿到這個標識后,就可以通過DeathRecipient機制獲取到Bp端異常退出的回調。這是AudioService維持靜音狀態正常變遷的一個基石。 **注意** 服務端把客戶端傳入的這個Binder對象作為客戶端的一個唯一標識,能做的事情不僅僅DeathRecipient這一個。還以這個標識為鍵創建一個Hashtable,用來保存每個客戶端相關信息。這在Android各個系統服務的實現中是一種很常見的用法。 另外,本例中傳入的mICallBack是直接從Binder類實例化出來的,是一個很原始的IBinder對象。進一步講,如果傳遞了一個通過AIDL定義的IBinder對象,這個對象就有了交互能力,服務端可以它向客戶端進行回調。在后面探討AudioFocus機制時會遇到這種情況。 #### 2. VolumeDeathHandler分析 我們繼續跟蹤AudioService.setStreamMute()的實現,記得注意第三個參數cb,它是代表特定客戶端的標識。 **AudioService.java-->AudioService.setStreamMute()** ``` public void setStreamMute(int streamType, booleanstate, IBinder cb) { // 只有可以靜音的流類型才能執行靜音操作。這說明,并不是所有的流都可以被靜音 if(isStreamAffectedByMute(streamType)) { // 直接調用了流類型對應的mStreamStates的mute()函數 // 這里沒有做那個令人討厭的流類型的映射。這是出于操作語義上的原因。讀者可以自行思考一下 mStreamStates[streamType].mute(cb, state); } } ``` 接下來是VolumeStreamState的mute()函數。VolumeStreamState的確是音量相關操作的核心類型。 **AudioService.java-->VolumeStreamState.mute()** ``` public synchronized void mute(IBinder cb, booleanstate) { // 這句話是一個重點,VolumeDeathHandler與cb一一對應 // 用來管理客戶端的靜音操作,并且監控客戶端的生命狀態 VolumeDeathHandler handler = getDeathHandler(cb, state); if(handler == null) { Log.e(TAG, "Could not get client deathhandler for stream: "+mStreamType); return; } // 通過VolumeDeathHandler執行靜音操作 handler.mute(state); } ``` 上述代碼引入了靜音控制的主角,VolumeDeathHandler,也許叫做MuteHandler更合適一些。它其實只有兩個成員變量,分別是mICallBack和mMuteCount。其中mICallBack保存了客戶端的傳進來的標識,mMuteCount則保存了當前客戶端執行靜音操作的引用計數。另外,它繼承自IBinder.DeathRecipient,所以它擁有監聽客戶端生命狀態的能力。而成員函數則只有兩個,分別是mute()和binderDied()。說到這里,再看看上面VolumeStreamState.mute()的實現,讀者能否先想想VolumeDeathHandler的具體實現是什么樣子的么? 繼續上面的腳步,看一下它的mute()函數。它的參數state的取值指定了進行靜音還是取消靜音。所以這個函數也就分成了兩部分,分別處理靜音與取消靜音兩個操作。其實,這完全可以放在兩個函數中完成。先看看靜音操作是怎么做的吧。 **AudioService.java-->VolumeDeathHandler.mute()part1** ``` public void mute(boolean state) { if (state) { // 靜音操作 if(mMuteCount == 0) { // 如果mMuteCount等于0,則表示客戶端是第一次執行靜音操作 //此時我們linkToDeath,開始對客戶端的生命狀況進行監聽 //這樣做的好處是可以避免非靜音狀態下對Binder資源的額外占用 try { // linkToDeath! 為什么要判斷是否為空?AudioManager不是寫死了會把一個有效的 // Binder傳遞進來么?原來AudioManager也可能會調用mute() // 此時的mICallback為空 if (mICallback != null) { mICallback.linkToDeath(this, 0); } // 保存的mDeathHandlers列表中去 mDeathHandlers.add(this); // muteCount() 我們在后面會介紹,這是全局的靜音操作的引用計數 // 如果它的返回值為0,則表示這個流目前還沒有被靜音 if (muteCount() == 0) { // 在這里設置流的音量為0 ......//你打出來的省略號咋這么小呢?^_^ } }catch (RemoteException e) { ...... } } // 引用計數加1 mMuteCount++; } else { // 暫時先不看取消靜音的操作 …… } } ``` 看明白了么?這個函數的條件嵌套比較多,仔細歸納一下,就會發現這段代碼的思路是非常清晰的。靜音操作根據條件滿足與否,有三個任務要做: - 無論什么條件下,只要執行了這個函數,靜音操作的引用計數都會加1。 - 如果這是客戶端第一次執行靜音,則開始監控其生命狀態,并把自己加入到VolumeStreamState的mDeathHandlers列表中去。這是這段代碼中很精練的一個操作,只有在客戶端執行過靜音操作后才會對其生命狀態感興趣,才有保存其VolumeDeathHandler的必要。 - 更進一步的,如果這是這個流類型第一次被靜音,則設置流音量為0,這才是真正的靜音動作。 不得不說,這段代碼是非常精練的,不是說代碼量少,而是它的行為非常干凈。決不會做多余的操作,也不會保存多余的變量。 下面我們要看一下取消靜音的操作。取消靜音作為靜音的逆操作,相信讀者已經可以想象得到取消靜音都做什么事情了吧?我們就不再對其進行說明了。 **AudioService.java-->VolumeDeathHandler.mute()part 2** ``` public void mute(boolean state) { if (state) { // 忽略掉靜音操作 ...... } else { if(mMuteCount == 0) { Log.e(TAG, "unexpected unmute for stream: "+mStreamType); }else { // 引用計數減1先 mMuteCount--; if (mMuteCount == 0) { // 如果這是客戶端最后一次有效地取消靜音 mDeathHandlers.remove(this); if (mICallback != null) { mICallback.unlinkToDeath(this, 0); } if (muteCount() == 0) { // 將流的音量值設置回靜音前的音量,也就是lastAudibleIndex …… } } } } } ``` 然后就剩下最后的binderDied()函數了。當客戶端發生異常,沒能取消其執行過的靜音操作時,需要替它完成它應該做卻沒做的事情。 **AudioService.java-->VolumeDeathHandler.binderDied()** ``` public void binderDied() { if(mMuteCount != 0) { mMuteCount = 1; mute(false); } } ``` 這個實現不難理解。讀者可以將自行分析一下為什么這么做可以消除意外退出的客戶端遺留下來的影響。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看