android常見面試大全

一,基礎部分

1,四大組件是什麼

1)Activity:用戶可操作的可視化界面,爲用戶提供一個完成操作指令的窗口。一個Activity通常是一個單獨的屏幕,Activity通過Intent來進行通信。Android中會維持一個Activity Stack,當一個新Activity創建時,它就會放到棧頂,這個Activity就處於運行狀態。

2)Service:服務,運行在手機後臺,適合執行不需和用戶交互且還需長期運行的任務。

3)ContentProvider:內容提供者,使一個應用程序的指定數據集提供給其他應用程序,其他應用可通過ContentResolver類從該內容提供者中獲取或存入數據。它提供了一種跨進程數據共享的方式,當數據被修改後,ContentResolver接口的notifyChange函數通知那些註冊監控特定URI的ContentObserver對象。

如果ContentProvider和調用者在同一進程中,ContentProvider的方法(query/insert/update/delete等)和調用者在同一線程中;如果ContentProvider和調用者不在同一進程,ContentProvider方法會運行在它自身進程的一個Binder線程中。

4)Broadcast Receiver: 廣播接收者,運用在應用程序間傳輸信息,可以使用廣播接收器來讓應用對一個外部事件做出響應。

2,四大組件的生命週期和簡單用法

1)Activity:onCreate()->onStart()->onResume()->onPause()->onStop()->onDestory()

onCreate():爲Activity設置佈局,此時界面還不可見;

onStart(): Activity可見但還不能與用戶交互,不能獲得焦點

onRestart(): 重新啓動Activity時被回調

onResume(): Activity可見且可與用戶進行交互

onPause(): 當前Activity暫停,不可與用戶交互,但還可見。在新Activity啓動前被系統調用保存現有的Activity中的持久數據、停止動畫等。

onStop(): 當Activity被新的Activity覆蓋不可見時被系統調用

onDestory(): 當Activity被系統銷燬殺掉或是由於內存不足時調用

2)Service

a) onBind方式綁定的:onCreate->onBind->onUnBind->onDestory(不管調用bindService幾次,onCreate只會調用一次,onStart不會被調用,建立連接後,service會一直運行,直到調用unBindService或是之前調用的bindService的Context不存在了,系統會自動停止Service,對應的onDestory會被調用)

b) startService啓動的:onCreate->onStartCommand->onDestory(start多次,onCreate只會被調用一次,onStart會調用多次,該service會在後臺運行,直至被調用stopService或是stopSelf)

c) 又被啓動又被綁定的服務,不管如何調用onCreate()只被調用一次,startService調用多少次,onStart就會被調用多少次,而unbindService不會停止服務,必須調用stopService或是stopSelf來停止服務。必須unbindService和stopService(stopSelf)同時都調用了纔會停止服務。

3)BroadcastReceiver

a) 動態註冊:存活週期是在Context.registerReceiver和Context.unregisterReceiver之間,BroadcastReceiver每次收到廣播都是使用註冊傳入的對象處理的。

b) 靜態註冊:進程在的情況下,receiver會正常收到廣播,調用onReceive方法;生命週期只存活在onReceive函數中,此方法結束,BroadcastReceiver就銷燬了。onReceive()只有十幾秒存活時間,在onReceive()內操作超過10S,就會報ANR。

進程不存在的情況,廣播相應的進程會被拉活,Application.onCreate會被調用,再調用onReceive。

4)ContentProvider:應該和應用的生命週期一樣,它屬於系統應用,應用啓動時,它會跟着初始化,應用關閉或被殺,它會跟着結束。

3,Android 進程通訊方式

  • bundle :
    由於Activity,Service,Receiver都是可以通過Intent來攜帶Bundle傳輸數據的,所以我們可以在一個進程中通過Intent將攜帶數據的Bundle發送到另一個進程的組件。(bundle只能傳遞三種類型,一是鍵值對的形式,二是鍵爲String類型,三是值爲Parcelable類型)
  • ContentProvider
    :ContentProvider是Android四大組件之一,以表格的方式來儲存數據,提供給外界,即Content
    Provider可以跨進程訪問其他應用程序中的數據
  • 文件
    :兩個進程可以到同一個文件去交換數據,我們不僅可以保存文本文件,還可以將對象持久化到文件,從另一個文件恢復。要注意的是,當併發讀/寫時可能會出現併發的問題。
  • Broadcast :Broadcast可以向android系統中所有應用程序發送廣播,而需要跨進程通訊的應用程序可以監聽這些廣播。
  • AIDL :AIDL通過定義服務端暴露的接口,以提供給客戶端來調用,AIDL使服務器可以並行處理。
  • Messager :Messenger封裝了AIDL之後只能串行運行,所以Messenger一般用作消息傳遞
  • Socket通信

4,Activity各種情況下的生命週期

1)兩個Activity(A->B)切換(B正常的Activity)的生命週期:onPause(A)->onCreate(B)->onStart(B)->onResume(B)->oStop(A)

這時如果按回退鍵回退到A onPause(B)->onRestart(A)->onStart(A)->onResume(A)->oStop(B)

如果在切換到B後調用了A.finish(),則會走到onDestory(A),這時點回退鍵會退出應用

2) 兩個Activity(A->B)切換(B透明主題的Activity或是Dialog風格的Acivity)的生命週期:onPause(A)->onCreate(B)->onStart(B)->onResume(B)

這時如果回退到A onPause(B)->onResume(A)->oStop(B)->onDestory(B)

3) Activity(A)啓動後點擊Home鍵再回到應用的生命週期:onPause(A)->oStop(A)->onRestart(A)->onStart(A)->onResume(A)

5,橫豎屏切換的時候,Activity 各種情況下的生命週期

1)切換橫屏時:onSaveInstanceState->onPause->onStop->onDestory->onCreate->onStart->onRestoreInstanceState->onResume

2) 切換豎屏時:會打印兩次相同的log

onSaveInstanceState->onPause->onStop->onDestory->onCreate->onStart->onRestoreInstanceState->onResume->onSaveInstanceState->onPause->onStop->onDestory->onCreate->onStart->onRestoreInstanceState->onResume

3)如果在AndroidMainfest.xml中修改該Activity的屬性,添加android:configChanges=“orientation”

橫豎屏切換,打印的log一樣,同1)

4)如果AndroidMainfest.xml中該Activity中的android:configChanges=“orientation|keyboardHidden”,則只會打印onConfigurationChanged

6,Activity與Fragment之間生命週期比較

Fragment生命週期:onAttach->onCreate->onCreateView->onActivityCreated->onStart->onResume->onPause->onStop->onDestoryView->onDestory->onDetach

切換到該Fragment:onAttach->onCreate->onCreateView->onActivityCreated->onStart->onResume

按下Power鍵:onPause->onSaveInstanceState->onStop

點亮屏幕解鎖:onStart->onRestoreInstanceState->onResume

切換到其他Fragment: onPause->onStop->onDestoryView

切回到該Fragment: onCreateView->onActivityCreated->onStart->onResume

退出應用:onPause->onStop->onDestoryView->onDestory->onDetach

7,Activity上有Dialog的時候按Home鍵時的生命週期

AlertDialog並不會影響Activity的生命週期,按Home鍵後纔會使Activity onPause->onStop,AlertDialog只是一個組件,並不會使Activity進入後臺。

8,兩個Activity 之間跳轉時必然會執行的是哪幾個方法

前一個Activity的onPause,後一個Activity的onResume

9,前臺切換後臺,再回到前臺,Activity生命週期回調方法。彈出Dialog,生命值週期回調方法。

1)前臺切換到後臺,會執行onPause->onStop,再回到前臺,會執行onRestart->onStart->onResume

2)彈出Dialog,並不會影響Activity生命週期。

10,Activity的四種啓動模式對比

1)standard:標準啓動模式(默認),每啓動一次Activity,都會創建一個實例,即使從ActivityA startActivity ActivityA,也會再次創建A的實例放於棧頂,當回退時,回到上一個ActivityA的實例。

2)singleTop:棧頂複用模式,每次啓動Activity,如果待啓動的Activity位於棧頂,則不會重新創建Activity的實例,即不會走onCreate->onStart,會直接進入Activity onPause->onNewIntent->onResume方法

3)singleInstance: 單一實例模式,整個手機操作系統裏只有一個該Activity實例存在,沒有其他Actvity,後續請求均不會創建新的Activity。若task中存在實例,執行實例的onNewIntent()。應用場景:鬧鐘、瀏覽器、電話。

4)singleTask:棧內複用,啓動的Activity如果在指定的taskAffinity的task棧中存在相應的實例,則會把它上面的Activity都出棧,直到當前Activity實例位於棧頂,執行相應的onNewIntent()方法。如果指定的task不存在,創建指定的taskAffinity的task,taskAffinity的作用,進入指寫taskAffinity的task,如果指定的task存在,將task移到前臺,如果指定的task不存在,創建指定的taskAffinity的task. 應用場景:應用的主頁面。

11,Activity狀態保存於恢復

Activity被主動回收時,如按下Back鍵,系統不會保存它的狀態,只有被動回收時,雖然這個Activity實例已被銷燬,但系統在新建一個Activity實例時,會帶上先前被回收Activity的信息。在當前Activity被銷燬前調用onSaveInstanceState(onPause和onStop之間保存),重新創建Activity後會在onCreate後調用onRestoreInstanceState(onStart和onResume之間被調用),它們的參數Bundle用來數據保存和讀取的。保存View狀態有兩個前提:View的子類必須實現了onSaveInstanceState; 必須要設定Id,這個ID作爲Bundle的Key

12,fragment各種情況下的生命週期

正常情況下的生命週期:onAttach->onCreate->onCreateView->onActivityCreated->onStart->onResume->onPause->onStop->onDestoryView->onDestory->onDetach

1)Fragment在Activity中replace onPause(舊)->onAttach->onCreate->onCreateView->onActivityCreated->onStart->onResume->onStop(舊)->onDestoryView(舊)

2)如果添加到backStack中,調用remove()方法fragment的方法會走到onDestoryView,但不會執行onDetach(),即fragment本身的實例是存在的,成員變量也存在,但是view被銷燬了。如果新替換的Fragment已在BackStack中,則不會執行onAttach->onCreate

13,說說ContentProvider、ContentResolver、ContentObserver 之間的關係

ContentProvider實現各個應用程序間數據共享,用來提供內容給別的應用操作。如聯繫人應用中就使用了ContentProvider,可以在自己應用中讀取和修改聯繫人信息,不過需要獲取相應的權限。它也只是一箇中間件,真正的數據源是文件或SQLite等。

ContentResolver內容解析者,用於獲取內容提供者提供的數據,通過ContentResolver.notifyChange(uri)發出消息

ContentObserver內容監聽者,可以監聽數據的改變狀態,觀察特定Uri引起的數據庫變化,繼而做一些相應的處理,類似於數據庫中的觸發器,當ContentObserver所觀察的Uri發生變化時,便會觸發它。

14,AlertDialog,popupWindow,Activity區別

1)Popupwindow在顯示之前一定要設置寬高,Dialog無此限制。

2)Popupwindow默認不會響應物理鍵盤的back,除非顯示設置了popup.setFocusable(true);而在點擊back的時候,Dialog會消失。

3)Popupwindow不會給頁面其他的部分添加蒙層,而Dialog會。

4)Popupwindow沒有標題,Dialog默認有標題,可以通過dialog.requestWindowFeature(Window.FEATURE_NO_TITLE)取消標題

5)二者顯示的時候都要設置Gravity。如果不設置,Dialog默認是Gravity.CENTER。

6)二者都有默認的背景,都可以通過setBackgroundDrawable(new ColorDrawable(android.R.color.transparent))去掉。

7)Popupwindow彈出後,取得了用戶操作的響應處理權限,使得其他UI控件不被觸發。而AlertDialog彈出後,點擊背景,AlertDialog會消失。

二,高級部分

1,Activity啓動流程(從Launcher開始)
在這裏插入圖片描述

①,第一階段: Launcher通知AMS要啓動新的Activity(在Launcher所在的進程執行)

  • Launcher.startActivitySafely //首先Launcher發起啓動Activity的請求
  • Activity.startActivity
  • Activity.startActivityForResult
  • Instrumentation.execStartActivity //交由Instrumentation代爲發起請求
  • ActivityManager.getService().startActivity //通過IActivityManagerSingleton.get()得到一個AMP代理對象
  • ActivityManagerProxy.startActivity //通過AMP代理通知AMS啓動activity

②,第二階段:AMS先校驗一下Activity的正確性,如果正確的話,會暫存一下Activity的信息。然後AMS會通知Launcher程序pause Activity(在AMS所在進程執行)

  • ActivityManagerService.startActivity
  • ActivityManagerService.startActivityAsUser
  • ActivityStackSupervisor.startActivityMayWait
  • ActivityStackSupervisor.startActivityLocked // 檢查有沒有在AndroidManifest中註冊
  • ActivityStackSupervisor.startActivityUncheckedLocked
  • ActivityStack.startActivityLocked // 判斷是否需要創建一個新的任務來啓動Activity。
  • ActivityStack.resumeTopActivityLocked // 獲取棧頂的activity,並通知Launcher應該pause掉這個Activity以便啓動新的activity。
  • ActivityStack.startPausingLocked
  • ApplicationThreadProxy.schedulePauseActivity

③,pause Launcher的Activity,並通知AMS已經paused(在Launcher所在進程執行)

  • ApplicationThread.schedulePauseActivity
  • ActivityThread.queueOrSendMessage
  • H.handleMessage
  • ActivityThread.handlePauseActivity
  • ActivityManagerProxy.activityPaused

④,檢查activity所在進程是否存在,如果存在,就直接通知這個進程,在該進程中啓動Activity;不存在的話,會調用Process.start創建一個新進程(執行在AMS進程)

  • ActivityManagerService.activityPaused
  • ActivityStack.activityPaused
  • ActivityStack.completePauseLocked
  • ActivityStack.resumeTopActivityLocked
  • ActivityStack.startSpecificActivityLocked
  • ActivityManagerService.startProcessLocked
  • Process.start // 在這裏創建了新進程,新的進程會導入ActivityThread類,並執行它的main函數。

⑤,創建ActivityThread實例,執行一些初始化操作,並綁定Application。如果Application不存在,會調用LoadedApk.makeApplication創建一個新的Application對象。之後進入Loop循環。(執行在新創建的app進程)

  • ActivityThread.main
  • ActivityThread.attach(false) //聲明不是系統進程
  • ActivityManagerProxy.attachApplication

⑥,處理新的應用進程發出的創建進程完成的通信請求,並通知新應用程序進程啓動目標Activity組件(執行在AMS進程)

  • ActivityManagerService.attachApplication // AMS綁定本地ApplicationThread對象,後續通過ApplicationThreadProxy來通信。
  • ActivityManagerService.attachApplicationLocked
  • ActivityStack.realStartActivityLocked //真正要啓動Activity了!
  • ApplicationThreadProxy.scheduleLaunchActivity //AMS通過ATP通知app進程啓動Activity

⑦,加載MainActivity類,調用onCreate聲明週期方法(執行在新啓動的app進程)

  • ApplicationThread.scheduleLaunchActivity //ApplicationThread發消息給AT
  • ActivityThread.queueOrSendMessage
  • H.handleMessage //AT的Handler來處理接收到的LAUNCH_ACTIVITY的消息
  • ActivityThread.handleLaunchActivity
  • ActivityThread.performLaunchActivity
  • Instrumentation.newActivity //調用Instrumentation類來新建一個Activity對象
  • Instrumentation.callActivityOnCreate
  • MainActivity.onCreate
  • ActivityThread.handleResumeActivity
  • AMP.activityResumed
  • AMS.activityResumed(AMS進程)

2,進程保活

此處延伸:進程的優先級是什麼

當前業界的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一樣躲避不了被殺的命運,爲了儘量避免被殺,還是老老實實去做好優化工作吧。

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

3,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事件。

4,AIDL理解

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

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接口的能力。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章