MediaSessionCompat::setMetadata呼叫時遇到的深坑
本文主要講解了一下幾個方面:
(1)bitmap.copy()發生np的原因及Config 為何為null;
(2)不同系統setMetadata的實現機制及其差異性對比;
(3)不同版本support 庫MediaSessioCompat::setMetadata實現差異。
一、深坑背景
既然是深坑,必然是難以發現(偶現問題),大家可能在想MediaSessionCompat::setMetadata()一個方法呼叫還未出現什麼問題,正因我也是這麼想,所以問題發生了 。
問題現場 :在RDM問題列表中發現了一個np問題 (只有幾例,上報機型均為小米系統,api19),來自bitmap.copy() ,對應到專案呼叫處 mMediaSessionCompat.setMetadata() 如下圖所示 ,這裡是專門針對小米系統鎖屏進行的相關處理。
一看便知 ,傳入的congfig為null導致 ,為什麼config為null,我們後面再講,先來看看為什麼setMetadata會導致bitmap.copy ,帶著疑問去看看setMetadata的呼叫過程。
二、MediaSessioCompat::setMetadata 呼叫過程
在講解MediaSessioCompat::setMetadata前,先了解一下RemoteControlClient、MediaSession等多媒體控制相關類。
RemoteControlClient 主要用於鎖屏狀態控制音樂播放,鎖屏介面由系統提供,在Android 4.0 (API 14)提供,目前已經被標記為deprecated(目前已推薦使用MediaSession)。 MediaSession 是一個專門解決媒體播放時介面和服務通訊問題的框架,在Android 5.0才被引進,可應用在鎖屏、耳機線控、藍芽耳機。
而這裡的MediaSessioCompat 是support包提供的一個相容性類 ,從命名就可以看出來,setMetadata方法作用主要是更新資料(包括歌曲名、歌手、背景圖、字幕等資訊),因此對於音訊類系統鎖屏是相當重要的。
MediaSessioCompat::setMetadata()內部實踐上呼叫的是 MediaSessionImpl::setMetadata,既然是相容類 ,對應的MediaSessionImpl 肯定在不同版本有著不同實現 (api 21 作為區分節點),如下:
(1)MediaSessionImplBase::setMetadata (api <21)
在MediaSessionImplBase內部 主要進行了兩大操作,先對metadata資料中的 bitmaps資料進行拷貝 (發現bitmap相關操作了),然後又對api 19 和 api 14 分別進行了區分(後面解釋為什麼會進行區分),呼叫各自的setMetadata。
沒錯,bitmap.copy()的np問題正是發生在這裡,通過Bitmap相關api註釋知,bitmap.getConfig()可能返回為null,奈何這竟然是一個系統bug,迭代了這麼多版本google竟未修復。
這裡的Config其實指的是 bitmap的型別 :可以看到確實有兩類返回的config為null
具體什麼情況為null了 ,我在Bitmapcreate Bitmap(Bitmap source, int x, int y, int width, int height, Matrix m, boolean filter) 實現中找到了蛛絲馬跡,如下圖中註釋:gif 檔案會產出 null configs,但是對於我們專案來說,專輯封面採用的都不是gif格式,因此對於bitmap.getConfig()返回為null還是為弄清(那位大神知道請告訴一下,謝謝)。
雖然這個np問題可以輕而易舉的解決,單本人不甘停留如此,還有有個疑問為什麼要clone bitmap相關資料(註釋已經說了,防止recycle),那在什麼時候會recycle 。
(2)在那裡進行recycle操作
在(1)中已經說過,MediaSessionImplBase裡面會進行兩部分操作,第二部分操作是setMetadata,其內部實現如下:
建立editor 、put 資料、最後apply。 這裡分別使用了RemoteControlClient.MetadataEditor和MediaMetadataEditor (api 19 才提供)。
apply()才是關鍵 ,內部實現如下:其中mOriginalArtWork就是專門用來快取封面的bitmap ,可能考慮到鎖屏比較頻繁,防止頻繁呼叫吧,但是bitmap.recycle() 不是在2.3.3以後就不推薦使用嗎,真不知道為何在此還要如此實現。
細心一點的同學可能發現,在這個裡面竟然呼叫了MediaSession::setMetadata()根據,前面對MediaSession(5.0 引進)介紹知,在5.0以下實現方式肯定不一致:
另外 ,在高版本中又是如何處理相關問題的了,帶著這些疑問我們直接分析MediaSession::setMetadata()方法即可。
三、MediaSession::setMetadata()
在第二部分,主要講解了MediaSessioCompat::setMetadata api 21以下的呼叫,在api >=21時,其內部呼叫的是 MediaSession::setMetadata(),具體如下:
這裡也是分為兩步 :更新metadata 資料,執行更新 。
相比api <21 情況,這裡並未clone 封面背景bitmap ,保證了一定效能。內部使用的是scaleBitmap 最後實際呼叫Bitmapcreate Bitmap(Bitmap source, int x, int y, int width, int height, Matrix m, boolean filter) ,整個過程簡單明瞭。
而對於執行更新,這裡採用的IPC 方式,上面的mBinder 其實是 ISession.aidl 物件,效率相比之前的提高不少。(這裡具體就不展開。)
四、不同版本support 庫MediaSessioCompat::setMetadata實現差異
前面講的MediaSessioCompat 是基於support-v4-23.4.0 版本,可以看到MediaSessioCompat為了配合RemoteContorlClient::apply() 方法中的 bitmap.recyle() , 在setMetadta內部對進行了Clone。
而在support-v4-22.2.1 中發現,並未對封面bitmap 進行可能,這種情況下,發生crash是必然的,可能正因如此,google在後面的support 庫修復了這個問題。support-v4-23.4.0版本發生np ,原因前面已經說了,是因為bitmap.getConfig()為null導致 (這種情況極其少,因而極難發現)。
感慨:本文主要記錄了一次系統填坑經歷 ;反思,在使用系統API時一定要全面弄清,儘量避免進坑。
相關文章
- 狀態模式中迴圈呼叫子元件時遇到的問題模式元件
- 短影片平臺開發時那些容易掉進去的“深坑”
- [求助]..新手!遇到struts呼叫sessionbean問題?SessionBean
- WebView上傳檔案的深坑與研究WebView
- 使用 redisson 時遇到的問題Redis
- Android Studio 2.2 jack深坑Android
- jfinal系統啟動時呼叫的方法和系統停止時呼叫的方法
- vue 克隆物件時遇到的問題Vue物件
- 刪除外部表時遇到的坑
- 使用constexpr時遇到的小坑
- 使用MySQL時遇到的各種坑MySql
- 學習Golang時遇到的似懂非懂的概念Golang
- 分析表時遇到BUG
- PL/SQL呼叫時使用呼叫者的許可權SQL
- 深坑 OR 福地?SAP應用上雲的這兩個星期!
- 總結:使用MyBatis Generator時遇到的坑MyBatis
- 使用React Hooks時遇到的錯誤提示ReactHook
- php部署到nginx時遇到的問題PHPNginx
- 使用Golang時遇到的一些坑Golang
- iOS時間格式化遇到的坑iOS
- 使用flashback database 特性時遇到的錯誤Database
- 我呼叫第三方介面遇到的13大坑
- tomcat在呼叫shared lib遇到的問題--gradleTomcatGradle
- Linq sum()時遇到NULLNull
- 介面呼叫超時的實現原理
- 使用flask的時候遇到的問題及其解答Flask
- 遷移Report Server DataBase時遇到的坑ServerDatabase
- sed 原地替換檔案時遇到的趣事
- 坑四:利用json模組時遇到的坑JSON
- java複製檔案時遇到的問題Java
- mysql原始碼安裝時遇到的問題MySql原始碼
- 安裝VisualSvn Server時遇到的問題Server
- 關於struts開發時遇到的問題
- 在釋出war包時遇到的問題
- JS呼叫時間的方法和計算JS
- Go併發呼叫的超時處理Go
- PHP呼叫webservice遇到 Soap WSDL Error - "failed to load external entityPHPWebErrorAI
- 什麼時候呼叫layoutSubviewsView