1. 程式人生 > 其它 >2021Android大廠高頻面試題,Android入門視訊教程

2021Android大廠高頻面試題,Android入門視訊教程

Android面試題含答案

1、Activity生命週期?

onCreate() -> onStart() -> onResume() -> onPause() -> onStop() -> onDetroy()

2、Service生命週期?

service 啟動方式有兩種,一種是通過startService()方式進行啟動,另一種是通過bindService()方式進行啟動。不同的啟動方式他們的生命週期是不一樣.

通過startService()這種方式啟動的service,生命週期是這樣:呼叫startService() → onCreate()→ onStartConmon()→ onDestroy()。這種方式啟動的話,需要注意一下幾個問題,第一:當我們通過startService被呼叫以後,多次在呼叫startService(),onCreate()方法也只會被呼叫一次,而onStartConmon()會被多次呼叫當我們呼叫stopService()的時候,onDestroy()就會被呼叫,從而銷燬服務。第二:當我們通過startService啟動時候,通過intent傳值,在onStartConmon()方法中獲取值的時候,一定要先判斷intent是否為null。

通過bindService()方式進行繫結,這種方式繫結service,生命週期走法:bindService→onCreate()→onBind()→unBind()→onDestroy() bingservice 這種方式進行啟動service好處是更加便利activity中操作service,比如加入service中有幾個方法,a,b ,如果要在activity中呼叫,在需要在activity獲取ServiceConnection物件,通過ServiceConnection來獲取service中內部類的類物件,然後通過這個類物件就可以呼叫類中的方法,當然這個類需要繼承Binder物件

3、Activity的啟動過程(不要回答生命週期)

app啟動的過程有兩種情況,第一種是從桌面launcher上點選相應的應用圖示,第二種是在activity中通過呼叫startActivity來啟動一個新的activity。

我們建立一個新的專案,預設的根activity都是MainActivity,而所有的activity都是儲存在堆疊中的,我們啟動一個新的activity就會放在上一個activity上面,而我們從桌面點選應用圖示的時候,由於launcher本身也是一個應用,當我們點選圖示的時候,系統就會呼叫startActivitySately(),一般情況下,我們所啟動的activity的相關資訊都會儲存在intent中,比如action,category等等。我們在安裝這個應用的時候,系統也會啟動一個PackaManagerService的管理服務,這個管理服務會對AndroidManifest.xml檔案進行解析,從而得到應用程式中的相關資訊,比如service,activity,Broadcast等等,然後獲得相關元件的資訊。當我們點選應用圖示的時候,就會呼叫startActivitySately()方法,而這個方法內部則是呼叫startActivty(),而startActivity()方法最終還是會呼叫startActivityForResult()這個方法。而在startActivityForResult()這個方法。因為startActivityForResult()方法是有返回結果的,所以系統就直接給一個-1,就表示不需要結果返回了。而startActivityForResult()這個方法實際是通過Instrumentation類中的execStartActivity()方法來啟動activity,Instrumentation這個類主要作用就是監控程式和系統之間的互動。而在這個execStartActivity()方法中會獲取ActivityManagerService的代理物件,通過這個代理物件進行啟動activity。啟動會就會呼叫一個checkStartActivityResult()方法,如果說沒有在配置清單中配置有這個元件,就會在這個方法中丟擲異常了。當然最後是呼叫的是Application.scheduleLaunchActivity()進行啟動activity,而這個方法中通過獲取得到一個ActivityClientRecord物件,而這個ActivityClientRecord通過handler來進行訊息的傳送,系統內部會將每一個activity元件使用ActivityClientRecord物件來進行描述,而ActivityClientRecord物件中儲存有一個LoaderApk物件,通過這個物件呼叫handleLaunchActivity來啟動activity元件,而頁面的生命週期方法也就是在這個方法中進行呼叫。

4、Broadcast註冊方式與區別

此處延伸:什麼情況下用動態註冊

Broadcast廣播,註冊方式主要有兩種.

第一種是靜態註冊,也可成為常駐型廣播,這種廣播需要在Androidmanifest.xml中進行註冊,這中方式註冊的廣播,不受頁面生命週期的影響,即使退出了頁面,也可以收到廣播這種廣播一般用於想開機自啟動啊等等,由於這種註冊的方式的廣播是常駐型廣播,所以會佔用CPU的資源。

第二種是動態註冊,而動態註冊的話,是在程式碼中註冊的,這種註冊方式也叫非常駐型廣播,收到生命週期的影響,退出頁面後,就不會收到廣播,我們通常運用在更新UI方面。這種註冊方式優先順序較高。最後需要解綁,否會會記憶體洩露

廣播是分為有序廣播和無序廣播。

5、HttpClient與HttpUrlConnection的區別

此處延伸:Volley裡用的哪種請求方式(2.3前HttpClient,2.3後HttpUrlConnection)

首先HttpClient和HttpUrlConnection 這兩種方式都支援Https協議,都是以流的形式進行上傳或者下載資料,也可以說是以流的形式進行資料的傳輸,還有ipv6,以及連線池等功能。HttpClient這個擁有非常多的API,所以如果想要進行擴充套件的話,並且不破壞它的相容性的話,很難進行擴充套件,也就是這個原因,Google在Android6.0的時候,直接就棄用了這個HttpClient.

而HttpUrlConnection相對來說就是比較輕量級了,API比較少,容易擴充套件,並且能夠滿足Android大部分的資料傳輸。比較經典的一個框架volley,在2.3版本以前都是使用HttpClient,在2.3以後就使用了HttpUrlConnection。

6、java虛擬機器和Dalvik虛擬機器的區別

Java虛擬機器:

1、java虛擬機器基於棧。 基於棧的機器必須使用指令來載入和操作棧上資料,所需指令更多更多。

2、java虛擬機器執行的是java位元組碼。(java類會被編譯成一個或多個位元組碼.class檔案)

Dalvik虛擬機器

  • 1、dalvik虛擬機器是基於暫存器的
  • 2、Dalvik執行的是自定義的.dex位元組碼格式。(java類被編譯成.class檔案後,會通過一個dx工具將所有的.class檔案轉換成一個.dex檔案,然後dalvik虛擬機器會從其中讀取指令和資料
  • 3、常量池已被修改為只使用32位的索引,以 簡化直譯器。
  • 4、一個應用,一個虛擬機器例項,一個程序(所有android應用的執行緒都是對應一個linux執行緒,都執行在自己的沙盒中,不同的應用在不同的程序中執行。每個android dalvik應用程式都被賦予了一個獨立的linux PID(app_*))

7、程序保活(不死程序)

  • 此處延伸:程序的優先順序是什麼

當前業界的Android程序保活手段主要分為 黑、白、灰 三種,其大致的實現思路如下:

  • 黑色保活 :不同的app程序,用廣播相互喚醒(包括利用系統提供的廣播進行喚醒)
  • 白色保活 :啟動前臺Service
  • 灰色保活 :利用系統的漏洞啟動前臺Service
  • 黑色保活

所謂黑色保活,就是利用不同的app程序使用廣播來進行相互喚醒。舉個3個比較常見的場景:

場景1 :開機,網路切換、拍照、拍視訊時候,利用系統產生的廣播喚醒app

場景2 :接入第三方SDK也會喚醒相應的app程序,如微信sdk會喚醒微信,支付寶sdk會喚醒支付寶。由此發散開去,就會直接觸發了下面的 場景3

場景3 :假如你手機裡裝了支付寶、淘寶、天貓、UC等阿里系的app,那麼你開啟任意一個阿里系的app後,有可能就順便把其他阿里系的app給喚醒了。(只是拿阿里打個比方,其實BAT系都差不多)

白色保活

白色保活手段非常簡單,就是呼叫系統api啟動一個前臺的Service程序,這樣會在系統的通知欄生成一個Notification,用來讓使用者知道有這樣一個app在執行著,哪怕當前的app退到了後臺。如下方的LBE和QQ音樂這樣:

灰色保活

灰色保活,這種保活手段是應用範圍最廣泛。它是利用系統的漏洞來啟動一個前臺的Service程序,與普通的啟動方式區別在於,它不會在系統通知欄處出現一個Notification,看起來就如同執行著一個後臺Service程序一樣。這樣做帶來的好處就是,使用者無法察覺到你執行著一個前臺程序(因為看不到Notification),但你的程序優先順序又是高於普通後臺程序的。那麼如何利用系統的漏洞呢,大致的實現思路和程式碼如下:

思路一:API < 18,啟動前臺Service時直接傳入new Notification();

思路二:API >= 18,同時啟動兩個id相同的前臺Service,然後再將後啟動的Service做stop處理

熟悉Android系統的童鞋都知道,系統出於體驗和效能上的考慮,app在退到後臺時系統並不會真正的kill掉這個程序,而是將其快取起來。開啟的應用越多,後臺快取的程序也越多。在系統記憶體不足的情況下,系統開始依據自身的一套程序回收機制來判斷要kill掉哪些程序,以騰出記憶體來供給需要的app。這套殺程序回收記憶體的機制就叫 Low Memory Killer ,它是基於Linux核心的 OOM Killer(Out-Of-Memory killer)機制誕生。

  • 程序的重要性,劃分5級:-
  • 前臺程序 (Foreground process)
  • 可見程序 (Visible process)
  • 服務程序 (Service process)
  • 後臺程序 (Background process)
  • 空程序 (Empty process)

瞭解完 Low Memory Killer,再科普一下oom_adj。什麼是oom_adj?它是linux核心分配給每個系統程序的一個值,代表程序的優先順序,程序回收機制就是根據這個優先順序來決定是否進行回收。對於oom_adj的作用,你只需要記住以下幾點即可:

程序的oom_adj越大,表示此程序優先順序越低,越容易被殺回收;越小,表示程序優先順序越高,越不容易被殺回收

普通app程序的oom_adj>=0,系統程序的oom_adj才可能<0

有些手機廠商把這些知名的app放入了自己的白名單中,保證了程序不死來提高使用者體驗(如微信、QQ、陌陌都在小米的白名單中)。如果從白名單中移除,他們終究還是和普通app一樣躲避不了被殺的命運,為了儘量避免被殺,還是老老實實去做好優化工作吧。

所以,程序保活的根本方案終究還是回到了效能優化上,程序永生不死終究是個徹頭徹尾的偽命題!

8、講解一下Context

Context是一個抽象基類。在翻譯為上下文,也可以理解為環境,是提供一些程式的執行環境基礎資訊。Context下有兩個子類,ContextWrapper是上下文功能的封裝類,而ContextImpl則是上下文功能的實現類。而ContextWrapper又有三個直接的子類, ContextThemeWrapper、Service和Application。其中,ContextThemeWrapper是一個帶主題的封裝類,而它有一個直接子類就是Activity,所以Activity和Service以及Application的Context是不一樣的,只有Activity需要主題,Service不需要主題。Context一共有三種類型,分別是Application、Activity和Service。這三個類雖然分別各種承擔著不同的作用,但它們都屬於Context的一種,而它們具體Context的功能則是由ContextImpl類去實現的,因此在絕大多數場景下,Activity、Service和Application這三種類型的Context都是可以通用的。不過有幾種場景比較特殊,比如啟動Activity,還有彈出Dialog。出於安全原因的考慮,Android是不允許Activity或Dialog憑空出現的,一個Activity的啟動必須要建立在另一個Activity的基礎之上,也就是以此形成的返回棧。而Dialog則必須在一個Activity上面彈出(除非是System Alert型別的Dialog),因此在這種場景下,我們只能使用Activity型別的Context,否則將會出錯。

getApplicationContext()和getApplication()方法得到的物件都是同一個application物件,只是物件的型別不一樣。

Context數量 = Activity數量 + Service數量 + 1 (1為Application)

9、理解Activity,View,Window三者關係

這個問題真的很不好回答。所以這裡先來個算是比較恰當的比喻來形容下它們的關係吧。Activity像一個工匠(控制單元),Window像窗戶(承載模型),View像窗花(顯示檢視)LayoutInflater像剪刀,Xml配置像窗花圖紙。

  • 1:Activity構造的時候會初始化一個Window,準確的說是PhoneWindow。
  • 2:這個PhoneWindow有一個“ViewRoot”,這個“ViewRoot”是一個View或者說ViewGroup,是最初始的根檢視。
  • 3:“ViewRoot”通過addView方法來一個個的新增View。比如TextView,Button等
  • 4:這些View的事件監聽,是由WindowManagerService來接受訊息,並且回撥Activity函式。比如onClickListener,onKeyDown等。

10、四種LaunchMode及其使用場景

此處延伸:棧(First In Last Out)與佇列(First In First Out)的區別

棧與佇列的區別:

  1. 佇列先進先出,棧先進後出

    \2. 對插入和刪除操作的”限定”。 棧是限定只能在表的一端進行插入和刪除操作的線性表。 佇列是限定只能在表的一端進行插入和在另一端進行刪除操作的線性表。

\3. 遍歷資料速度不同

standard 模式

這是預設模式,每次啟用Activity時都會建立Activity例項,並放入任務棧中。使用場景:大多數Activity。

  • singleTop 模式

如果在任務的棧頂正好存在該Activity的例項,就重用該例項( 會呼叫例項的 onNewIntent() ),否則就會建立新的例項並放入棧頂,即使棧中已經存在該Activity的例項,只要不在棧頂,都會建立新的例項。使用場景如新聞類或者閱讀類App的內容頁面。

  • singleTask 模式

如果在棧中已經有該Activity的例項,就重用該例項(會呼叫例項的 onNewIntent() )。重用時,會讓該例項回到棧頂,因此在它上面的例項將會被移出棧。如果棧中不存在該例項,將會建立新的例項放入棧中。使用場景如瀏覽器的主介面。不管從多少個應用啟動瀏覽器,只會啟動主介面一次,其餘情況都會走onNewIntent,並且會清空主介面上面的其他頁面。

  • singleInstance 模式

在一個新棧中建立該Activity的例項,並讓多個應用共享該棧中的該Activity例項。一旦該模式的Activity例項已經存在於某個棧中,任何應用再啟用該Activity時都會重用該棧中的例項( 會呼叫例項的 onNewIntent() )。其效果相當於多個應用共享一個應用,不管誰啟用該 Activity 都會進入同一個應用中。使用場景如鬧鈴提醒,將鬧鈴提醒與鬧鈴設定分離。singleInstance不要用於中間頁面,如果用於中間頁面,跳轉會有問題,比如:A -> B (singleInstance) -> C,完全退出後,在此啟動,首先開啟的是B。

11、View的繪製流程

自定義控制元件

1、組合控制元件。這種自定義控制元件不需要我們自己繪製,而是使用原生控制元件組合成的新控制元件。如標題欄。

2、繼承原有的控制元件。這種自定義控制元件在原生控制元件提供的方法外,可以自己新增一些方法。如製作圓角,圓形圖片。

3、完全自定義控制元件:這個View上所展現的內容全部都是我們自己繪製出來的。比如說製作水波紋進度條。

View的繪製流程:OnMeasure()——>OnLayout()——>OnDraw()

第一步:OnMeasure():測量檢視大小。從頂層父View到子View遞迴呼叫measure方法,measure方法又回撥OnMeasure。

第二步:OnLayout():確定View位置,進行頁面佈局。從頂層父View向子View的遞迴呼叫view.layout方法的過程,即父View根據上一步measure子View所得到的佈局大小和佈局引數,將子View放在合適的位置上。

第三步:OnDraw():繪製檢視。ViewRoot建立一個Canvas物件,然後呼叫OnDraw()。六個步驟:①、繪製檢視的背景;②、儲存畫布的圖層(Layer);③、繪製View的內容;④、繪製View子檢視,如果沒有就不用;

⑤、還原圖層(Layer);⑥、繪製滾動條。

12、View,ViewGroup事件分發

\1. Touch事件分發中只有兩個主角:ViewGroup和View。ViewGroup包含onInterceptTouchEvent、dispatchTouchEvent、onTouchEvent三個相關事件。View包含dispatchTouchEvent、onTouchEvent兩個相關事件。其中ViewGroup又繼承於View。

2.ViewGroup和View組成了一個樹狀結構,根節點為Activity內部包含的一個ViwGroup。

3.觸控事件由Action_Down、Action_Move、Aciton_UP組成,其中一次完整的觸控事件中,Down和Up都只有一個,Move有若干個,可以為0個。

4.當Acitivty接收到Touch事件時,將遍歷子View進行Down事件的分發。ViewGroup的遍歷可以看成是遞迴的。分發的目的是為了找到真正要處理本次完整觸控事件的View,這個View會在onTouchuEvent結果返回true。

5.當某個子View返回true時,會中止Down事件的分發,同時在ViewGroup中記錄該子View。接下去的Move和Up事件將由該子View直接進行處理。由於子View是儲存在ViewGroup中的,多層ViewGroup的節點結構時,上級ViewGroup儲存的會是真實處理事件的View所在的ViewGroup物件:如ViewGroup0-ViewGroup1-TextView的結構中,TextView返回了true,它將被儲存在ViewGroup1中,而ViewGroup1也會返回true,被儲存在ViewGroup0中。當Move和UP事件來時,會先從ViewGroup0傳遞至ViewGroup1,再由ViewGroup1傳遞至TextView。

6.當ViewGroup中所有子View都不捕獲Down事件時,將觸發ViewGroup自身的onTouch事件。觸發的方式是呼叫super.dispatchTouchEvent函式,即父類View的dispatchTouchEvent方法。在所有子View都不處理的情況下,觸發Acitivity的onTouchEvent方法。

7.onInterceptTouchEvent有兩個作用:1.攔截Down事件的分發。2.中止Up和Move事件向目標View傳遞,使得目標View所在的ViewGroup捕獲Up和Move事件。

13、儲存Activity狀態

onSaveInstanceState(Bundle)會在activity轉入後臺狀態之前被呼叫,也就是onStop()方法之前,onPause方法之後被呼叫;

14、Android中的幾種動畫

幀動畫:指通過指定每一幀的圖片和播放時間,有序的進行播放而形成動畫效果,比如想聽的律動條。

補間動畫:指通過指定View的初始狀態、變化時間、方式,通過一系列的演算法去進行圖形變換,從而形成動畫效果,主要有Alpha、Scale、Translate、Rotate四種效果。注意:只是在檢視層實現了動畫效果,並沒有真正改變View的屬性,比如滑動列表,改變標題欄的透明度。

屬性動畫:在Android3.0的時候才支援,通過不斷的改變View的屬性,不斷的重繪而形成動畫效果。相比於檢視動畫,View的屬性是真正改變了。比如view的旋轉,放大,縮小。

15、Android中跨程序通訊的幾種方式

Android 跨程序通訊,像intent,contentProvider,廣播,service都可以跨程序通訊。

intent:這種跨程序方式並不是訪問記憶體的形式,它需要傳遞一個uri,比如說打電話。

contentProvider:這種形式,是使用資料共享的形式進行資料共享。

service:遠端服務,aidl

廣播

16、AIDL理解

此處延伸:簡述Binder

AIDL: 每一個程序都有自己的Dalvik VM例項,都有自己的一塊獨立的記憶體,都在自己的記憶體上儲存自己的資料,執行著自己的操作,都在自己的那片狹小的空間裡過完自己的一生。而aidl就類似與兩個程序之間的橋樑,使得兩個程序之間可以進行資料的傳輸,跨程序通訊有多種選擇,比如 BroadcastReceiver , Messenger 等,但是 BroadcastReceiver 佔用的系統資源比較多,如果是頻繁的跨程序通訊的話顯然是不可取的;Messenger 進行跨程序通訊時請求佇列是同步進行的,無法併發執行。

Binde機制簡單理解:

在Android系統的Binder機制中,是有Client,Service,ServiceManager,Binder驅動程式組成的,其中Client,service,Service Manager執行在使用者空間,Binder驅動程式是執行在核心空間的。而Binder就是把這4種元件粘合在一塊的粘合劑,其中核心的元件就是Binder驅動程式,Service Manager提供輔助管理的功能,而Client和Service正是在Binder驅動程式和Service Manager提供的基礎設施上實現C/S 之間的通訊。其中Binder驅動程式提供裝置檔案/dev/binder與使用者控制元件進行互動,

Client、Service,Service Manager通過open和ioctl檔案操作相應的方法與Binder驅動程式進行通訊。而Client和Service之間的程序間通訊是通過Binder驅動程式間接實現的。而Binder Manager是一個守護程序,用來管理Service,並向Client提供查詢Service介面的能力。

17、Handler的原理

Android中主執行緒是不能進行耗時操作的,子執行緒是不能進行更新UI的。所以就有了handler,它的作用就是實現執行緒之間的通訊。

handler整個流程中,主要有四個物件,handler,Message,MessageQueue,Looper。當應用建立的時候,就會在主執行緒中建立handler物件,

我們通過要傳送的訊息儲存到Message中,handler通過呼叫sendMessage方法將Message傳送到MessageQueue中,Looper物件就會不斷的呼叫loop()方法

不斷的從MessageQueue中取出Message交給handler進行處理。從而實現執行緒之間的通訊。

18、Binder機制原理

在Android系統的Binder機制中,是有Client,Service,ServiceManager,Binder驅動程式組成的,其中Client,service,Service Manager執行在使用者空間,Binder驅動程式是執行在核心空間的。而Binder就是把這4種元件粘合在一塊的粘合劑,其中核心的元件就是Binder驅動程式,Service Manager提供輔助管理的功能,而Client和Service正是在Binder驅動程式和Service Manager提供的基礎設施上實現C/S 之間的通訊。其中Binder驅動程式提供裝置檔案/dev/binder與使用者控制元件進行互動,Client、Service,Service Manager通過open和ioctl檔案操作相應的方法與Binder驅動程式進行通訊。而Client和Service之間的程序間通訊是通過Binder驅動程式間接實現的。而Binder Manager是一個守護程序,用來管理Service,並向Client提供查詢Service介面的能力。

19、熱修復的原理

我們知道Java虛擬機器 —— JVM 是載入類的class檔案的,而Android虛擬機器——Dalvik/ART VM 是載入類的dex檔案,

而他們載入類的時候都需要ClassLoader,ClassLoader有一個子類BaseDexClassLoader,而BaseDexClassLoader下有一個

陣列——DexPathList,是用來存放dex檔案,當BaseDexClassLoader通過呼叫findClass方法時,實際上就是遍歷陣列,

找到相應的dex檔案,找到,則直接將它return。而熱修復的解決方法就是將新的dex新增到該集合中,並且是在舊的dex的前面,

所以就會優先被取出來並且return返回。

20、Android記憶體洩露及管理

  • (1)記憶體溢位(OOM)和記憶體洩露(物件無法被回收)的區別。
  • (2)引起記憶體洩露的原因

(3) 記憶體洩露檢測工具 ——→LeakCanary

記憶體溢位 out of memory:是指程式在申請記憶體時,沒有足夠的記憶體空間供其使用,出現out of memory;比如申請了一個integer,但給它存了long才能存下的數,那就是記憶體溢位。記憶體溢位通俗的講就是記憶體不夠用。

記憶體洩露 memory leak:是指程式在申請記憶體後,無法釋放已申請的記憶體空間,一次記憶體洩露危害可以忽略,但記憶體洩露堆積後果很嚴重,無論多少記憶體,遲早會被佔光

總結

最後為了幫助大家深刻理解Android相關知識點的原理以及面試相關知識,這裡放上相關的我搜集整理的Android開發中高階必知必會核心筆記,共計2968頁PDF、58w字,囊括Android開發648個知識點,我把技術點整理成了視訊和PDF(實際上比預期多花了不少精力),包知識脈絡 + 諸多細節。

開源分享:《Android學習筆記總結+移動架構視訊+大廠面試真題+專案實戰原始碼》

網上學習 Android的資料一大堆,但如果學到的知識不成體系,遇到問題時只是淺嘗輒止,不再深入研究,那麼很難做到真正的技術提升。希望這份系統化的技術體系對大家有一個方向參考。

2021年雖然路途坎坷,都在說Android要沒落,但是,不要慌,做自己的計劃,學自己的習,競爭無處不在,每個行業都是如此。相信自己,沒有做不到的,只有想不到的。

雖然面試失敗了,但我也不會放棄入職位元組跳動的決心的!建議大家面試之前都要有充分的準備,順順利利的拿到自己心儀的offer。