字节跳动资深面试官亲述:面试应该注意哪些问题?
01面試=做匹配
面試官的根本目的在于考察你這個人是否與招聘崗位相匹配,衡量能否勝任工作,我們在面試中要做到的就是讓面試官相信我們能夠與應聘崗位相匹配。
針對一些面試題做了總結:
1.請簡單進行一下自我介紹
首先請報出自己的姓名和身份。可能應試者與面試考官打招呼時,已經將此告訴了對方,而且考官們完全可以從你的報名表、簡歷等材料中了解這些情況,但仍請你主動提及。這是禮貌的需要,還可以加深考官對你的印象。
其次,你可以簡單地介紹一下你的學歷、工作經歷等基本個人情況。請提供給考官關于你個人情況的基本的、完整的信息,如:學歷、工作經歷、家庭概況、興趣愛好、理想與報負等。 這部分的陳述務必簡明扼要、抓住要點。例如介紹自己的學歷,一般只需談本專科以上的學歷。工作單位如果多,選幾個有代表性的或者你認為重要的介紹,就可以了,但這些內容一定要和面試及應考職位有關系。請保證敘述的線索清晰,一個結構混亂、內容過長的開場自,會給考官們留下雜亂無章、個性不清晰的印象,并且讓考官倦怠,削弱對繼續進行的面試的興趣和注意力。
應試者還要注意這部份內容應與個人簡歷、報名材料上的有關內容相一致,不要有出入。在介紹這些內容時,應避免書面語言的嚴整與拘束,而使用靈活的口頭語進行組織。這些個人基本情況的介紹沒有對或錯的問題——都屬于中性問題,但如果因此而大意就不妥了。
接下來由這部份個人基本情況,自然地過渡到一兩個自己本科或工作期間圓滿完成的事件,以這一兩個例子來形象地、明晰他說明自己的經驗與能力,例如:在學校擔任學生干部時成功組織的活動;或者如何投入到社會實踐中,利用自己的專長為社會公眾服務;或者自己在專業上取得的重要成績以及出色的學術成就。
接下來要著重結合你的職業理想說明你應考這個公務員職位的原因,這一點相當重要。你可以談你對應考單位或職務的認識了解,說明你選擇這個單位或職務的強烈愿望。原先有工作單位的應試者應解釋清楚自己放棄原來的工作而做出新的職業選擇的原因。你還可以談如果你被錄取,那么你將怎樣盡職盡責地工作,并不斷根據需要完善和發展自己。當然這些都應密切聯系你的價值觀與職業觀。不過,如果你將自己描述為不食人間煙火的、不計較個人利益的“圣人”,那么考官們對你的求職動機的信任,就要大打折扣了。
這里我們介紹了一條清晰的線索,便于你組織你的自我介紹。為了保證結構明確,有條有理,你可以多用短句子以便于口語表述,并且在段與段之間使用過渡句子,口語也要注意思路、敘述語言的流暢,盡量避免顛三倒四,同一句話反復說幾遍的“粘糊勁,同時不要用過于隨便的表述。
2.你認為自己最大的缺點是什么?
思路:
1、 不宜說自己沒缺點。
2、 不宜把那些明顯的優點說成缺點。
3、 不宜說出嚴重影響所應聘工作的缺點。
4、 不宜說出令人不放心、不舒服的缺點。
5、 可以說出一些對于所應聘工作“無關緊要”的缺點,甚至是一些表面上看是缺點,從工作的角度看卻是優點的缺點。
答:我的工作執行力很高,領導給我安排的任務我也能較快的完成,但是可能在工作的時候會少一些深入的獨立思考,對整個工作的安排缺乏戰略眼光,對于這方面能力需要我進一步的努力,我也將繼續學習,通過閱讀、向前輩請教等改善自己的不足。
3.你是如何看待加班的?
答:工作中難免會出現各種各樣的突發狀況,我完全可以接受突發臨時性的加班,以確保項目或者工作的順利推進,因為這些都是我應當負責的。但是以加班為榮,或者只是為了其他人都沒走的這種加班,我想我無法接受。如果是我自身的原因導致無法順利完成工作而不得不加班,那么我也會尋找原因,提高個人工作效率,嘗試解決問題。
4.你還有什么想問的嗎?
答:如果我有幸加入貴公司/團隊/部門,那么前期我將主要負責哪方面的工作內容呢?/“您覺得我要勝任這個崗位,還需要在哪方面多下功夫呢?”
Tips:從工作體驗、工作內容、崗位發展等角度入手都是很不錯的選擇。
02 Android面試中有哪些常見問題匯總&答題思路
目錄:
1.網絡
2.Java 基礎&容器&同步&設計模式
3.Java 虛擬機&內存結構&GC&類加載&四種引用&動態代理
4.Android 基礎&性能優化&Framwork
5.Android 模塊化&熱修復&熱更新&打包&混淆&壓縮
6.音視頻&FFmpeg&播放器
1、網絡
網絡協議模型
**應用層:**負責處理特定的應用程序細節
HTTP、FTP、DNS
**傳輸層:**為兩臺主機提供端到端的基礎通信
TCP、UDP
**網絡層:**控制分組傳輸、路由選擇等
IP
**鏈路層:**操作系統設備驅動程序、網卡相關接口
TCP 和 UDP 區別
TCP 連接;可靠;有序;面向字節流;速度慢;較重量;全雙工;適用于文件傳輸、瀏覽器等
全雙工:A 給 B 發消息的同時,B 也能給 A 發
半雙工:A 給 B 發消息的同時,B 不能給 A 發
UDP 無連接;不可靠;無序;面向報文;速度快;輕量;適用于即時通訊、視頻通話等
TCP 三次握手
A:你能聽到嗎?
B:我能聽到,你能聽到嗎?
A:我能聽到,開始吧
A 和 B 兩方都要能確保:我說的話,你能聽到;你說的話,我能聽到。所以需要三次握手
TCP 四次揮手
A:我說完了
B:我知道了,等一下,我可能還沒說完
B:我也說完了
A:我知道了,結束吧
B 收到 A 結束的消息后 B 可能還沒說完,沒法立即回復結束標示,只能等說完后再告訴 A :我說完了。
POST 和 GET 區別
Get 參數放在 url 中;Post 參數放在 request Body 中
Get 可能不安全,因為參數放在 url 中
HTTPS
HTTP 是超文本傳輸協議,明文傳輸;HTTPS 使用 SSL 協議對 HTTP 傳輸數據進行了加密
HTTP 默認 80 端口;HTTPS 默認 443 端口
優點:安全
缺點:費時、SSL 證書收費,加密能力還是有限的,但是比 HTTP 強多了
2、Java 基礎&容器&同步&設計模式
StringBuilder、StringBuffer、+、String.concat 鏈接字符串:
StringBuffer 線程安全,StringBuilder 線程不安全
+實際上是用 StringBuilder 來實現的,所以非循環體可以直接用 +,循環體不行,因為會頻繁創建 StringBuilder
String.concat 實質是 new String ,效率也低,耗時排序:StringBuilder < StringBuffer < concat < +
Java 泛型擦除
修飾成員變量等類結構相關的泛型不會被擦除
容器類泛型會被擦除
ArrayList、LinkedList
ArrayList
基于數組實現,查找快:o(1),增刪慢:o(n)
初始容量為10,擴容通過 System.arrayCopy 方法
LinkedList
基于雙向鏈表實現,查找慢:o(n),增刪快:o(1)
封裝了隊列和棧的調用
HashMap 、HashTable
HashMap
基于數組和鏈表實現,數組是 HashMap 的主體;鏈表是為解決哈希沖突而存在的
當發生哈希沖突且鏈表 size 大于閾值時會擴容,JAVA 8 會將鏈表轉為紅黑樹提高性能
允許 key/value 為 null
HashTable
數據結構和 HashMap 一樣
不允許 value 為 null
線程安全
ArrayMap、SparseArray
ArrayMap
1.基于兩個數組實現,一個存放 hash;一個存放鍵值對。擴容的時候只需要數組拷貝,不需要重建哈希表
2.內存利用率高
3.不適合存大量數據,因為會對 key 進行二分法查找(1000以下)
SparseArray
1.基于兩個數組實現,int 做 key
2.內存利用率高
3.不適合存大量數據,因為會對 key 進行二分法查找(1000以下)
volatile 關鍵字
只能用來修飾變量,適用修飾可能被多線程同時訪問的變量
相當于輕量級的 synchronized,volatitle 能保證有序性(禁用指令重排序)、可見性;后者還能保證原子性
變量位于主內存中,每個線程還有自己的工作內存,變量在自己線程的工作內存中有份拷貝,線程直接操作的是這個拷貝
被 volatile 修飾的變量改變后會立即同步到主內存,保持變量的可見性。
雙重檢查單例,為什么要加 volatile?
1.volatile想要解決的問題是,在另一個線程中想要使用instance,發現instance!=null,但是實際上instance還未初始化完畢這個問題
2.將instance =newInstance();拆分為3句話是。1.分配內存2.初始化3.將instance指向分配的內存空
3.volatile可以禁止指令重排序,確保先執行2,后執行3
wait 和 sleep
sleep 是 Thread 的靜態方法,可以在任何地方調用
wait 是 Object 的成員方法,只能在 synchronized 代碼塊中調用,否則會報 IllegalMonitorStateException 非法監控狀態異常
sleep 不會釋放共享資源鎖,wait 會釋放共享資源鎖
lock 和 synchronized
synchronized 是 Java 關鍵字,內置特性;Lock 是一個接口
synchronized 會自動釋放鎖;lock 需要手動釋放,所以需要寫到 try catch 塊中并在 finally 中釋放鎖
synchronized 無法中斷等待鎖;lock 可以中斷
Lock 可以提高多個線程進行讀/寫操作的效率
競爭資源激烈時,lock 的性能會明顯的優于 synchronized
可重入鎖
定義:已經獲取到鎖后,再次調用同步代碼塊/嘗試獲取鎖時不必重新去申請鎖,可以直接執行相關代碼
ReentrantLock 和 synchronized 都是可重入鎖
公平鎖
定義:等待時間最久的線程會優先獲得鎖
非公平鎖無法保證哪個線程獲取到鎖,synchronized 就是非公平鎖
ReentrantLock 默認時非公平鎖,可以設置為公平鎖
樂觀鎖和悲觀鎖
**悲觀鎖:**線程一旦得到鎖,其他線程就掛起等待,適用于寫入操作頻繁的場景;synchronized 就是悲觀鎖
**樂觀鎖:**假設沒有沖突,不加鎖,更新數據時判斷該數據是否過期,過期的話則不進行數據更新,適用于讀取操作頻繁的場景
**樂觀鎖 CAS:**Compare And Swap,更新數據時先比較原值是否相等,不相等則表示數據過去,不進行數據更新
****樂觀鎖實現:AtomicInteger、AtomicLong、AtomicBoolean
死鎖 4 個必要條件
互斥
占有且等待
不可搶占
循環等待
synchronized 原理
每個對象都有一個監視器鎖:monitor,同步代碼塊會執行 monitorenter 開始,motnitorexit 結束
wait/notify 就依賴 monitor 監視器,所以在非同步代碼塊中執行會報 IllegalMonitorStateException 異常
3、Java 虛擬機&內存結構&GC&類加載&四種引用&動態代理
JVM
定義:可以理解成一個虛構的計算機,解釋自己的字節碼指令集映射到本地 CPU 或 OS 的指令集,上層只需關注 Class 文件,與操作系統無關,實現跨平臺
Kotlin 就是能解釋成 Class 文件,所以可以跑在 JVM 上
JVM 內存模型
Java 多線程之間是通過共享內存來通信的,每個線程都有自己的本地內存
共享變量存放于主內存中,線程會拷貝一份共享變量到本地內存
volatile 關鍵字就是給內存模型服務的,用來保證內存可見性和順序性
JVM 內存結構
線程私有:
1.程序計數器:記錄正在執行的字節碼指令地址,若正在執行 Native 方法則為空
2.虛擬機棧:執行方法時把方法所需數據存為一個棧幀入棧,執行完后出棧
3.本地方法棧:同虛擬機棧,但是針對的是 Native 方法
線程共享:
1.堆:存儲 Java 實例,GC 主要區域,分代收集 GC 方法會吧堆劃分為新生代、老年代
2.方法區:存儲類信息,常量池,靜態變量等數據
GC
回收區域:只針對堆、方法區;線程私有區域數據會隨線程結束銷毀,不用回收
回收類型:
1.堆中的對象
分代收集 GC 方法會吧堆劃分為新生代、老年代
新生代:新建小對象會進入新生代;通過復制算法回收對象
老年代:新建大對象及老對象會進入老年代;通過標記-清除算法回收對象
2.方法區中的類信息、常量池
判斷一個對象是否可被回收:
1.引用計數法
缺點:循環引用
2.可達性分析法
定義:從 GC ROOT 開始搜索,不可達的對象都是可以被回收的
GC ROOT
1.虛擬機棧/本地方法棧中引用的對象
2.方法區中常量/靜態變量引用的對象
四種引用
強引用:不會被回收
軟引用:內存不足時會被回收
弱引用:gc 時會被回收
虛引用:無法通過虛引用得到對象,可以監聽對象的回收
ClassLoader
類的生命周期:
1.加載;2.驗證;3.準備;4.解析;5.初始化;6.使用;7.卸載
類加載過程:
1.加載:獲取類的二進制字節流;生成方法區的運行時存儲結構;在內存中生成 Class 對象
2.驗證:確保該 Class 字節流符合虛擬機要求
3.準備:初始化靜態變量
4.解析:將常量池的符號引用替換為直接引用
5.初始化:執行靜態塊代碼、類變量賦值
類加載時機:
1.實例化對象
2.調用類的靜態方法
3.調用類的靜態變量(放入常量池的常量除外)
類加載器:負責加載 class 文件
分類:
1.引導類加載器 - 沒有父類加載器
2.拓展類加載器 - 繼承自引導類加載器
3.系統類加載器 - 繼承自拓展類加載器
雙親委托模型:
當要加載一個 class 時,會先逐層向上讓父加載器先加載,加載失敗才會自己加載
為什么叫雙親?不考慮自定義加載器,系統類加載器需要網上詢問兩層,所以叫雙親
判斷是否是同一個類時,除了類信息,還必須時同一個類加載器
優點:
防止重復加載,父加載器加載過了就沒必要加載了
安全,防止篡改核心庫類
動態代理原理及實現
InvocationHandler 接口,動態代理類需要實現這個接口
Proxy.newProxyInstance,用于動態創建代理對象
Retrofit 應用: Retrofit 通過動態代理,為我們定義的請求接口都生成一個動態代理對象,實現請求
4、Android 基礎&性能優化&Framwork
Activity 啟動模式
standard 標準模式
singleTop 棧頂復用模式,
推送點擊消息界面
singleTask 棧內復用模式,
首頁
singleInstance 單例模式,單獨位于一個任務棧中
撥打電話界面
細節:
taskAffinity:任務相關性,用于指定任務棧名稱,默認為應用包名
allowTaskReparenting:允許轉移任務棧
View 工作原理
DecorView (FrameLayout)
LinearLayout
titlebar
Content
調用 setContentView 設置的 View
ViewRoot 的 performTraversals 方法調用觸發開始 View 的繪制,然后會依次調用:
performMeasure:遍歷 View 的 measure 測量尺寸
performLayout:遍歷 View 的 layout 確定位置
performDraw:遍歷 View 的 draw 繪制
事件分發機制
一個 MotionEvent 產生后,按 Activity -> Window -> decorView -> View 順序傳遞,View 傳遞過程就是事件分發,主要依賴三個方法:
dispatchTouchEvent:用于分發事件,只要接受到點擊事件就會被調用,返回結果表示是否消耗了當前事件
onInterceptTouchEvent:用于判斷是否攔截事件,當 ViewGroup 確定要攔截事件后,該事件序列都不會再觸發調用此 ViewGroup 的 onIntercept
onTouchEvent:用于處理事件,返回結果表示是否處理了當前事件,未處理則傳遞給父容器處理
細節:
一個事件序列只能被一個 View 攔截且消耗
View 沒有 onIntercept 方法,直接調用 onTouchEvent 處理
OnTouchListener 優先級比 OnTouchEvent 高,onClickListener 優先級最低
requestDisallowInterceptTouchEvent 可以屏蔽父容器 onIntercet 方法的調用
Window 、 WindowManager、WMS、SurfaceFlinger
**Window:**抽象概念不是實際存在的,而是以 View 的形式存在,通過 PhoneWindow 實現
**WindowManager:**外界訪問 Window 的入口,內部與 WMS 交互是個 IPC 過程
**WMS:**管理窗口 Surface 的布局和次序,作為系統級服務單獨運行在一個進程
**SurfaceFlinger:**將 WMS 維護的窗口按一定次序混合后顯示到屏幕上
View 動畫、幀動畫及屬性動畫
View 動畫:
作用對象是 View,可用 xml 定義,建議 xml 實現比較易讀
支持四種效果:平移、縮放、旋轉、透明度
幀動畫:
通過 AnimationDrawable 實現,容易 OOM
屬性動畫:
可作用于任何對象,可用 xml 定義,Android 3 引入,建議代碼實現比較靈活
包括 ObjectAnimator、ValuetAnimator、AnimatorSet
時間插值器:根據時間流逝的百分比計算當前屬性改變的百分比
系統預置勻速、加速、減速等插值器
類型估值器:根據當前屬性改變的百分比計算改變后的屬性值
系統預置整型、浮點、色值等類型估值器
使用注意事項:
避免使用幀動畫,容易OOM
界面銷毀時停止動畫,避免內存泄漏
開啟硬件加速,提高動畫流暢性 ,硬件加速:
將 cpu 一部分工作分擔給 gpu ,使用 gpu 完成繪制工作
從工作分攤和繪制機制兩個方面優化了繪制速度
Handler、MessageQueue、Looper
Handler:開發直接接觸的類,內部持有 MessageQueue 和 Looper
MessageQueue:消息隊列,內部通過單鏈表存儲消息
Looper:內部持有 MessageQueue,循環查看是否有新消息,有就處理,沒就阻塞
如何實現阻塞:通過 nativePollOnce 方法,基于 Linux epoll 事件管理機制
為什么主線程不會因為 Looper 阻塞:系統每 16ms 會發送一個刷新 UI 消息喚醒
MVC、MVP、MVVM
MVP:Model:處理數據;View:控制視圖;Presenter:分離 Activity 和 Model
MVVM:Model:處理獲取保存數據;View:控制視圖;ViewModel:數據容器
使用 Jetpack 組件架構的 LiveData、ViewModel 便捷實現 MVVM
Serializable、Parcelable
Serializable :Java 序列化方式,適用于存儲和網絡傳輸,serialVersionUID 用于確定反序列化和類版本是否一致,不一致時反序列化回失敗
Parcelable :Android 序列化方式,適用于組件通信數據傳遞,性能高,因為不像 Serializable 一樣有大量反射操作,頻繁 GC
Binder
Android 進程間通信的中流砥柱,基于客戶端-服務端通信方式
使用 mmap 一次數據拷貝實現 IPC,傳統 IPC:用戶A空間->內核->用戶B空間;mmap 將內核與用戶B空間映射,實現直接從用戶A空間->用戶B空間
BinderPool 可避免創建多 Service
IPC 方式
Intent extras、Bundle:要求傳遞數據能被序列化,實現 Parcelable、Serializable ,適用于四大組件通信
文件共享:適用于交換簡單的數據實時性不高的場景
AIDL:AIDL 接口實質上是系統提供給我們可以方便實現 BInder 的工具
Android Interface Definition Language,可實現跨進程調用方法
服務端:將暴漏給客戶端的接口聲明在 AIDL 文件中,創建 Service 實現 AIDL 接口并監聽客戶端連接請求
客戶端:綁定服務端 Service ,綁定成功后拿到服務端 Binder 對象轉為 AIDL 接口調用
RemoteCallbackList 實現跨進程接口監聽,同個 Binder 對象做 key 存儲客戶端注冊的 listener
監聽 Binder 斷開:1.Binder.linkToDeath 設置死亡代理;2. onServiceDisconnected 回調
Messenger:基于 AIDL 實現,服務端串行處理,主要用于傳遞消息,適用于低并發一對多通信
ContentProvider:基于 Binder 實現,適用于一對多進程間數據共享
Socket:TCP、UDP,適用于網絡數據交換
Android 系統啟動流程
按電源鍵 -> 加載引導程序 BootLoader 到 RAM -> 執行 BootLoader 程序啟動內核 -> 啟動 init 進程 -> 啟動 Zygote 和各種守護進程 ->
啟動 System Server 服務進程開啟 AMS、WMS 等 -> 啟動 Launcher 應用進程
App 啟動流程
Launcher 中點擊一個應用圖標 -> 通過 AMS 查找應用進程,若不存在就通過 Zygote 進程 fork
進程保活
進程優先級:1.前臺進程 ;2.可見進程;3.服務進程;4.后臺進程;5.空進程
進程被 kill 場景:1.切到后臺內存不足時被殺;2.切到后臺廠商省電機制殺死;3.用戶主動清理
保活方式:
1.Activity 提權:掛一個 1像素 Activity 將進程優先級提高到前臺進程
2.Service 提權:啟動一個前臺服務(API>18會有正在運行通知欄)
3.廣播拉活
4.Service 拉活
5.JobScheduler 定時任務拉活
6.雙進程拉活
網絡優化及檢測
速度:1.GZIP 壓縮(okhttp 自動支持);2.Protocol Buffer 替代 json;3.優化圖片/文件流量;4.IP 直連省去 DNS 解析時間
成功率:1.失敗重試策略;
流量:1.GZIP 壓縮(okhttp 自動支持);2.Protocol Buffer 替代 json;3.優化圖片/文件流量;5.文件下載斷點續傳 ;6.緩存
協議層的優化,比如更優的 http 版本等
監控:Charles 抓包、Network Monitor 監控流量
UI卡頓優化
減少布局層級及控件復雜度,避免過度繪制
使用 include、merge、viewstub
優化繪制過程,避免在 Draw 中頻繁創建對象、做耗時操作
內存泄漏場景及規避
1.靜態變量、單例強引跟生命周期相關的數據或資源,包括 EventBus
2.游標、IO 流等資源忘記主動釋放
3.界面相關動畫在界面銷毀時及時暫停
4.內部類持有外部類引用導致的內存泄漏
handler 內部類內存泄漏規避:1.使用靜態內部類+弱引用 2.界面銷毀時清空消息隊列
檢測:Android Studio Profiler
LeakCanary 原理
通過弱引用和引用隊列監控對象是否被回收
比如 Activity 銷毀時開始監控此對象,檢測到未被回收則主動 gc ,然后繼續監控
OOM 場景及規避
加載大圖:減小圖片
內存泄漏:規避內存泄漏
5、Android 模塊化&熱修復&熱更新&打包&混淆&壓縮
Dalvik 和 ART
Dalvik
谷歌設計專用于 Android 平臺的 Java 虛擬機,可直接運行 .dex 文件,適合內存和處理速度有限的系統
JVM 指令集是基于棧的;Dalvik 指令集是基于寄存器的,代碼執行效率更優
ART
Dalvik 每次運行都要將字節碼轉換成機器碼;ART 在應用安裝時就會轉換成機器碼,執行速度更快
ART 存儲機器碼占用空間更大,空間換時間
APK 打包流程
1.aapt 打包資源文件生成 R.java 文件;aidl 生成 java 文件
2.將 java 文件編譯為 class 文件
3.將工程及第三方的 class 文件轉換成 dex 文件
4.將 dex 文件、so、編譯過的資源、原始資源等打包成 apk 文件
5.簽名
6.資源文件對齊,減少運行時內存
App 安裝過程
首先要解壓 APK,資源、so等放到應用目錄
Dalvik 會將 dex 處理成 ODEX ;ART 會將 dex 處理成 OAT;
OAT 包含 dex 和安裝時編譯的機器碼
組件化路由實現
ARoute:通過 APT 解析 @Route 等注解,結合 JavaPoet 生成路由表,即路由與 Activity 的映射關系
6、音視頻&FFmpeg&播放器
FFmpeg
基于命令方式實現了一個音視頻編輯 App:
https://github.com/yhaolpz/FFmpegCmd
集成編譯了 AAC、MP3、H264 編碼器
播放器原理
視頻播放原理:(mp4、flv)-> 解封裝 -> (mp3/aac、h264/h265)-> 解碼 -> (pcm、yuv)-> 音視頻同步 -> 渲染播放
音視頻同步:
選擇參考時鐘源:音頻時間戳、視頻時間戳和外部時間三者選擇一個作為參考時鐘源(一般選擇音頻,因為人對音頻更敏感,ijk 默認也是音頻)
通過等待或丟幀將視頻流與參考時鐘源對齊,實現同步
IjkPlayer 原理
集成了 MediaPlayer、ExoPlayer 和 IjkPlayer 三種實現,其中 IjkPlayer 基于 FFmpeg 的 ffplay
音頻輸出方式:AudioTrack、OpenSL ES;視頻輸出方式:NativeWindow、OpenGL ES
03總結
Android架構學習進階是一條漫長而艱苦的道路,不能靠一時激情,更不是熬幾天幾夜就能學好的,必須養成平時努力學習的習慣。所以:貴在堅持!
總結
以上是生活随笔為你收集整理的字节跳动资深面试官亲述:面试应该注意哪些问题?的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: IE:免去脱机浏览中的麻烦(转)
- 下一篇: 优秀实践采购团队的8个要点