20道25K+Android工程師面試必問面試題
很多朋友都或多或少經歷過很多面試,而有的人拿到了自己心儀的offer,有的人卻被拒之門外。那麼今天整理了一份面試經常會問到的題目,希望可以幫助到更多的人。
本文講解:
- 我們為什麼要選擇離職
- 面試必問面試題
- 如何選擇心儀的公司
一.我們為何選擇離職
- 工資跟不上消費
- 上班找不到歸宿感和成績感,上班感覺和坐牢一樣
- 在公司沒有發展空間(之前我有一篇介紹選擇公司注重薪資和個人薪資的文章,可以參考從BAT這種公司平薪跳槽頭條,是否值得?)
二.25K+Android工程師必問面試題
1.APK安裝過程
應用安裝涉及到如下幾個目錄:- system/app:系統自帶的應用程序,無法刪除
- data/app:用戶程序安裝的目錄,有刪除許可權。安裝時把apk文件複製到此目錄
- data/data:存放應用程序的數據
- data/dalvik-cache:將apk中的dex文件安裝到dalvik-cache目錄下
複製APK安裝包到data/app目錄下,解壓並掃描安裝包,把dex文件(Dalvik位元組碼)保存到dalvik-cache目錄,並在data/data目錄下創建對應的應用數據目錄
2.invalidate()和postInvalidate() 的區別
invalidate()是用來刷新View的,必須是在UI線程中進行工作。比如在修改某個view的顯示時,調用invalidate()才能看到重新繪製的界面。
postInvalidate()在工作者線程中被調用。3.Parcelable和Serializable區別
Parcelable的性能比Serializable好,在內存開銷方面較小,所以在內存間數據傳輸時推薦使用Parcelable,如activity間傳輸數據,而Serializable可將數據持久化方便保存,所以在需要保存或網路傳輸數據時選擇Serializable,因為android不同版本Parcelable可能不同,所以不推薦使用Parcelable進行數據持久化。
Serializable序列化不保存靜態變數,可以使用Transient關鍵字對部分欄位不進行序列化,也可以覆蓋writeObject、readObject方法以實現序列化過程自定義。
4.Android裏跨進程傳遞數據的幾種方案
- Binder
- Socket/LocalSocket
- 共享內存
5.匿名共享內存,使用場景
在Android系統中,提供了獨特的匿名共享內存子系統Ashmem(Anonymous Shared Memory),它以驅動程序的形式實現在內核空間中。它有兩個特點,一是能夠輔助內存管理系統來有效地管理不再使用的內存塊,二是它通過Binder進程間通信機制來實現進程間的內存共享。
ashmem並像Binder是Android重新自己搞的一套東西,而是利用了Linux的 tmpfs文件系統。tmpfs是一種可以基於RAM或是SWAP的高速文件系統,然後可以拿它來實現不同進程間的內存共享。
大致思路和流程是:
- Proc A 通過 tmpfs 創建一塊共享區域,得到這塊區域的 fd(文件描述符)
- Proc A 在 fd 上 mmap 一片內存區域到本進程用於共享數據
- Proc A 通過某種方法把 fd 倒騰給 Proc B
- Proc B 在接到的 fd 上同樣 mmap 相同的區域到本進程
- 然後 A、B 在 mmap 到本進程中的內存中讀、寫,對方都能看到了
其實核心點就是創建一塊共享區域,然後2個進程同時把這片區域 mmap 到本進程,然後讀寫就像本進程的內存一樣。這裡要解釋下第3步,為什麼要倒騰 fd,因為在 linux 中 fd 只是對本進程是唯一的,在 Proc A 中打開一個文件得到一個 fd,但是把這個打開的 fd 直接放到 Proc B 中,Proc B 是無法直接使用的。但是文件是唯一的,就是說一個文件(file)可以被打開多次,每打開一次就有一個 fd(文件描述符),所以對於同一個文件來說,需要某種轉化,把 Proc A 中的 fd 轉化成 Proc B 中的 fd。這樣 Proc B 才能通過 fd mmap 同樣的共享內存文件。
使用場景:進程間大量數據傳輸
6.ContentProvider實現原理
ContentProvider 有以下兩個特點:
- 封裝:對數據進行封裝,提供統一的介面,使用者完全不必關心這些數據是在DB,XML、Preferences或者網路請求來的。當項目需求要改變數據來源時,使用我們的地方完全不需要修改。
- 提供一種跨進程數據共享的方式。
Content Provider組件在不同應用程序之間傳輸數據是基於匿名共享內存機制來實現的。其主要的調用過程:
①通過ContentResolver先查找對應給定Uri的ContentProvider,返回對應的BinderProxy
- 如果該Provider尚未被調用進程使用過:
- 通過ServiceManager查找activity service得到ActivityManagerService對應BinderProxy
- 調用BinderProxy的transcat方法發送GET_CONTENT_PROVIDER_TRANSACTION命令,得到對應ContentProvider的BinderProxy。
- 如果該Provider已被調用進程使用過,則調用進程會保留使用過provider的HashMap。此時直接從此表查詢即得。
②調用BinderProxy的query()
7.如何使用ContentProvider進行批量操作?
通常進行數據的批量操作我們都會使用「事務」,但是ContentProvider如何進行批量操作呢?創建 ContentProviderOperation 對象數組,然後使用 ContentResolver.applyBatch() 將其分派給內容提供程序。您需將內容提供程序的授權傳遞給此方法,而不是特定內容 URI。這樣可使數組中的每個 ContentProviderOperation 對象都能適用於其他表。調用 ContentResolver.applyBatch() 會返回結果數組。
同時我們還可以通過ContentObserver對數據進行觀察:
- 創建我們特定的ContentObserver派生類,必須重載onChange()方法去處理回調後的功能實現
- 利用context.getContentResolover()獲得ContentResolove對象,接著調用registerContentObserver()方法去註冊內容觀察者,為指定的Uri註冊一個ContentObserver派生類實例,當給定的Uri發生改變時,回調該實例對象去處理。
- 由於ContentObserver的生命週期不同步於Activity和Service等,因此,在不需要時,需要手動的調用unregisterContentObserver()去取消註冊。
8.廣播註冊後不解除註冊會有什麼問題?(內存泄露)
我們可以通過兩種方式註冊BroadcastReceiver,一是在Activity啟動過程中通過代碼動態註冊,二是在AndroidManifest.xml文件中利用<receiver>標籤進行靜態註冊。
- 對於第一種方法,我們需要養成一個良好的習慣:在Activity進入停止或者銷毀狀態的時候使用unregisterReceiver方法將註冊的BroadcastReceiver註銷掉。
- 對於<receiver>標籤進行註冊的,那麼該對象的實例在onReceive被調用之後就會在任意時間內被銷毀。
9.屬性動畫(Property Animation)和補間動畫(Tween Animation)的區別
10.BrocastReceive裡面可不可以執行耗時操作?
11.Android優化工具:TraceView和Systrace
12.Dalvik與ART的區別?
13.Android動態許可權?
14.ViewPager如何判斷左右滑動?
實現OnPageChangeListener並重寫onPageScrolled方法,通過參數進行判斷。
15.ListView與RecyclerView
16.描述一下Android手機啟動過程和App啟動過程?
Android手機啟動過程當我們開機時,首先是啟動Linux內核,在Linux內核中首先啟動的是init進程,這個進程會去讀取配置文件systemcore
配置文件,這個文件中配置了Android系統中第一個進程Zygote進程。
ootdirinit.rc
啟動Zygote進程 --> 創建AppRuntime(Android運行環境) --> 啟動虛擬機 --> 在虛擬機中註冊JNI方法 --> 初始化進程通信使用的Socket(用於接收AMS的請求) --> 啟動系統服務進程 --> 初始化時區、鍵盤佈局等通用信息 --> 啟動Binder線程池 --> 初始化系統服務(包括PMS,AMS等等) --> 啟動Launcher
App啟動過程