Android視訊開發進階(part5-ExoPlayer分析1,ExoPlayer的handler)

b10l07發表於2017-06-28

最近公司的活一直很多時間也很緊,加上忙搬家所以好久沒有更新了。。。今晚剛剛好專案做得差不多,忙裡偷閒更新一下

之前一直說要做一次ExoPlayer(這裡會用ExoPlayer2作為例子)的原始碼分析,想了一下,還是先介紹一下ExoPlayer的程式碼結構比較合適,原因有以下幾點,也算是最近的一些感悟和大家分享:

  • 1.其實很多文章,關於框架的原始碼分析都太過深入,其實本質就變成了一次程式碼跟蹤,這樣不是不好,畢竟看程式碼也是能力的一種。但是更多的情況下我們看程式碼,尤其是一些優秀的第三方框架,我們不是希望把程式碼100%背下來,而是學習第三方框架原始碼的優秀之處,看過一次原始碼,要至少明白他的優點在哪,精髓在哪。比如看完Retrofit,我們體會到了這個框架的怎麼進行解耦,怎麼運用註解,看完Volley,我們明白了一個短小精悍的網路庫怎麼做多執行緒,怎麼運用Cache,怎麼進行request的分發等等等等。所以我自己的感覺是需要更多的從整體去理解框架會更有幫助一些。
  • 2.很多朋友在學習的時候都太著急,一個框架還沒用熟就老是急著想做“原始碼分析”。我個人的觀點先擺出來,學習一個框架的原始碼,一定要帶著問題去看,不能盲目的進行程式碼跟蹤,那樣一點意義都沒有。要帶著問題,從深度再慢慢擴充套件到廣度,這樣循序漸進的過程才比較科學。有心的朋友可以試著去谷歌上搜尋RxJava source code anaylysis和RxJava原始碼分析,你可以發現,英文的RxJava原始碼分析幾乎沒人做,而中文的文章卻一大堆。仔細想想,這個原因到底是什麼?其實就是國內的應用使用者太多,我們國內的開發者需要對第三方庫(俗稱輪子)做各種各樣的定製(customisation),那麼就免不了對框架進行原始碼的解析。而國外的應用使用者量級與國內壓根沒法比,沒有各式各樣“苛刻”的使用者要求,自然沒有人去做什麼原始碼分析。還是那個觀點,需要帶著問題去看框架,如果沒問題,給自己找一個問題。

所以在開始一次原始碼的結構分析之前,大家先問問自己,我使用過這個ExoPlayer沒有?使用的深度如何?是否只是按照doc做了一個sample,doc上面初始化ExoPlayer的引數和各種構件都代表什麼意思?對ExoPlayer的使用上有沒有什麼疑惑?

說了這麼多廢話,希望也不要打擊大家看原始碼的熱情,只不過學的勤,不如學的巧,掌握更科學的方法可以事半功倍,那何樂而不為。學習這件事本身也是需要耐得住性子。。。so。。。

不要緊張,我們們來段freestyle壓壓驚,開始分析了!

1777208-ed7d2974acd76929.gif

首先ExoPlayer的入口自然是ExoPlayerImplInternal了,在建立ExoPlayer物件之後,ExoPlayer會通過handler,根據當前自身的狀態去不停發放訊息,然後自己同時接受這些訊息。
比如當我們呼叫ExoPlayer的prepare()方法時,其實我們就用ExoPlayer的handler去傳送了一條訊息MSG_PREPARE

傳送之後,ExoPlayerImplInternal物件自己又接受它,再去處理這條訊息。

最後再叫ExoPlayer所有的MediaSource進行準備prepare。

又或者再看看MSG_DO_SOME_WORK這個訊息發放出去之後,ExoPlayer做了什麼

大家知道在建立ExoPlayer的時候我們需要傳入一個renderer陣列,包括Video,Audio或者字幕的TextRenderer,他們每個都負責渲染Render自己負責的那一部分,在ExoPlayer裡面就是這麼一個簡單的for迴圈,搞定。

在一個dosomeWork()結束之後,通過handler再發一次MSG_DO_SOME_WORK

大家可以自己觀察一下其他MSG是用來幹嘛的,其實稍微看看就可以發現,都是和Playback相關的一些操作,比如seek,pause,release等等。

那麼其實到現在為止,ExoPlayer從整體上是怎麼工作,它的大概結構就很清楚了,用一個圖來表達一下。

user在建立ExoPlayer之後,呼叫任何的方法都是傳送一條message給他的handler,根據訊息的不通,ExoPlayer把訊息分發給不同的component,比如prepare就會把訊息分發給MediaResource,do_some_work會把訊息分發給Render,根據當前的進度去渲染視訊,音訊和字幕。在處理完一個訊息之後,會根據當前狀態傳送下一個訊息給ExoPlayerImplInternnal。在一個不停止的情況下,訊息佇列一般都是:

1.MSG_PREPARE

2.MSG_PERIOD_PREPARED

3.MSG_DO_SOME_WORK........不停的do some work...

整個ExoPlayer就是靠Handler來進行狀態維護的,不光只是ExoPlayerImplInternal這個類,其他的很多類比如LoadControl啊等等都是靠Handler來做狀態維護,和訊息發放,尤其是ExoPlayer的事件分放部分,都需要使用者自己傳入一個handler。可能這對初次使用的同學會造成一定的困擾。

不過在理解了ExoPlayer的大概結構之後,相信為何需要這個Handler的原因大家應該都能理解了。

ExoPlayer本身就是利用handler進行事件分發,和自身的狀態控制,任何使用者的操作,在ExoPlayer內部的實現都是會變成一個handler能處理的Message,再根據message的內容,ExoPlayer會讓不同的構件進行相應的操作,再根據操作的結果發下一個訊息。

這次的分析就先到此為止,下次我會開始分析MediaResource部分,也就是我們每次呼叫prepare()方法之後,我們到底在prepare(準備)什麼?

晚安!

相關文章