Android面試題整理-3

轉載自:android阿里面試題錦集


前幾天突然就經歷了阿里Android實習內推的電面,感覺有好多以前看過的東西都忘記了,然後又複習了一下,找了很多阿里的面經總結了一下,希望對大家有幫助,下面的知識點大多出自 android開發藝術探索,而且很多都是我自己的總結,方便自己記憶,如果想深入可以去看看這本書。

1.安卓事件分發機制,請詳細說下整個流程


事件分發(面試).png

2.安卓view繪製機制和加載過程,請詳細說下整個流程

  • 1.ViewRootImpl會調用performTraversals(),其內部會調用performMeasure()、performLayout、performDraw()。
  • 2.performMeasure()會調用最外層的ViewGroup的measure()-->onMeasure(),ViewGroup的onMeasure()是抽象方法,但其提供了measureChildren(),這之中會遍歷子View然後循環調用measureChild()這之中會用getChildMeasureSpec()+父View的MeasureSpec+子View的LayoutParam一起獲取本View的MeasureSpec,然後調用子View的measure()到View的onMeasure()-->setMeasureDimension(getDefaultSize(),getDefaultSize()),getDefaultSize()默認返回measureSpec的測量數值,所以繼承View進行自定義的wrap_content需要重寫。
  • 3.performLayout()會調用最外層的ViewGroup的layout(l,t,r,b),本View在其中使用setFrame()設置本View的四個頂點位置。在onLayout(抽象方法)中確定子View的位置,如LinearLayout會遍歷子View,循環調用setChildFrame()-->子View.layout()。
  • 4.performDraw()會調用最外層ViewGroup的draw():其中會先後調用background.draw()(繪製背景)、onDraw()(繪製自己)、dispatchDraw()(繪製子View)、onDrawScrollBars()(繪製裝飾)。
  • 5.MeasureSpec由2位SpecMode(UNSPECIFIED、EXACTLY(對應精確值和match_parent)、AT_MOST(對應warp_content))和30位SpecSize組成一個int,DecorView的MeasureSpec由窗口大小和其LayoutParams決定,其他View由父View的MeasureSpec和本View的LayoutParams決定。ViewGroup中有getChildMeasureSpec()來獲取子View的MeasureSpec。
  • 6.三種方式獲取measure()後的寬高:
    • 1.Activity#onWindowFocusChange()中調用獲取
    • 2.view.post(Runnable)將獲取的代碼投遞到消息隊列的尾部。
    • 3.ViewTreeObservable.

3.activty的加載過程 請詳細介紹下:

  • 1.Activity中最終到startActivityForResult()(mMainThread.getApplicationThread()傳入了一個ApplicationThread檢查APT)
    ->Instrumentation#execStartActivity()和checkStartActivityResult()(這是在啓動了Activity之後判斷Activity是否啓動成功,例如沒有在AM中註冊那麼就會報錯)
    ->ActivityManagerNative.getDefault().startActivity()(類似AIDL,實現了IAM,實際是由遠端的AMS實現startActivity())
    ->ActivityStackSupervisor#startActivityMayWait()
    ->ActivityStack#resumeTopActivityInnerLocked
    ->ActivityStackSupervisor#realStartActivityLocked()(在這裏調用APT的scheduleLaunchActivity,也是AIDL,不過是在遠端調起了本進程Application線程)
    ->ApplicationThread#scheduleLaunchActivity()(這是本進程的一個線程,用於作爲Service端來接受AMS client端的調起)
    ->ActivityThread#handleLaunchActivity()(接收內部類H的消息,ApplicationThread線程發送LAUNCH_ACTIVITY消息給H)
    ->最終在ActivityThread#performLaunchActivity()中實現Activity的啓動完成了以下幾件事:
  • 2.從傳入的ActivityClientRecord中獲取待啓動的Activity的組件信息
  • 3.創建類加載器,使用Instrumentation#newActivity()加載Activity對象
  • 4.調用LoadedApk.makeApplication方法嘗試創建Application,由於單例所以不會重複創建。
  • 5.創建Context的實現類ContextImpl對象,並通過Activity#attach()完成數據初始化和Context建立聯繫,因爲Activity是Context的橋接類,
    最後就是創建和關聯window,讓Window接收的事件傳給Activity,在Window的創建過程中會調用ViewRootImpl的performTraversals()初始化View。
  • 6.Instrumentation#callActivityOnCreate()->Activity#performCreate()->Activity#onCreate().onCreate()中會通過Activity#setContentView()調用PhoneWindow的setContentView()
    更新界面。

4.Activity的啓動模式:

  • 1.standard:默認標準模式,每啓動一個都會創建一個實例,
  • 2.singleTop:棧頂複用,如果在棧頂就調用onNewIntent複用,從onResume()開始
  • 3.singleTask:棧內複用,本棧內只要用該類型Activity就會調到棧頂複用,從onResume()開始
  • 4.singleInstance:單例模式,除了3中特性,系統會單獨給該Activity創建一個棧,

5.Activity緩存方法:

  • 1.配置改變導致Activity被殺死,橫屏變豎屏:在onStop之前會調用onSaveInstanceState()保存數據在重建Activity之後,會在onStart()之後調用onRestoreInstanceState(),並把保存下來的Bundle傳給onCreate()和它會默認重建Activity當前的視圖,我們可以在onCreate()中,回覆自己的數據。
  • 2.內存不足殺掉Activity,優先級分別是:前臺可見,可見非前臺,後臺。

6.Service的生命週期,兩種啓動方法,有什麼區別:

  • 1.context.startService() ->onCreate()- >onStart()->Service running-->(如果調用context.stopService() )->onDestroy() ->Service shut down
    • 1.如果Service還沒有運行,則調用onCreate()然後調用onStart();
    • 2.如果Service已經運行,則只調用onStart(),所以一個Service的onStart方法可能會重複調用多次。
    • 3.調用stopService的時候直接onDestroy,
    • 4.如果是調用者自己直接退出而沒有調用stopService的話,Service會一直在後臺運行。該Service的調用者再啓動起來後可以通過stopService關閉Service。
  • 2.context.bindService()->onCreate()->onBind()->Service running-->onUnbind() -> onDestroy() ->Service stop
    • 1.onBind將返回給客戶端一個IBind接口實例,IBind允許客戶端回調服務的方法,比如得到Service運行的狀態或其他操作。
    • 2.這個時候會把調用者和Service綁定在一起,Context退出了,Service就會調用onUnbind->onDestroy相應退出。
    • 3.所以調用bindService的生命週期爲:onCreate --> onBind(只一次,不可多次綁定) --> onUnbind --> onDestory。

7.怎麼保證service不被殺死

  • 1.提升service優先級
  • 2.提升service進程優先級
  • 3.onDestroy方法裏重啓service

8.廣播的兩種註冊方法,有什麼區別。

  • 1.靜態註冊:如果有廣播信息來,你寫的廣播接收器同樣的能接受到,比如系統的一些廣播。
  • 2.動態註冊:當應用程序結束了,廣播自然就沒有了,一些自己定義的廣播

9.Intent可以傳遞哪些數據類型

  • 1.Serializable
  • 2.charsequence: 主要用來傳遞String,char等
  • 3.parcelable
  • 4.Bundle

10.Json有什麼優劣勢

  • 1.JSON的速度要遠遠快於XML
  • 2.JSON相對於XML來講,數據的體積小
  • 3.JSON對數據的描述性比XML較差

11.動畫有哪幾類,各有什麼特點:

  • 1.動畫的基本原理:其實就是利用插值器和估值器,來計算出各個時刻View的屬性,然後通過改變View的屬性來,實現View的動畫效果。
  • 2.View動畫:只是影像變化,view的實際位置還在原來的地方。
  • 3.幀動畫是在xml中定義好一系列圖片之後,使用AnimationDrawable來播放的動畫。
  • 4.View的屬性動畫:
    • 1.插值器:作用是根據時間的流逝的百分比來計算屬性改變的百分比
    • 2.估值器:在1的基礎上由這個東西來計算出屬性到底變化了多少數值的類

12.Handler、Loop消息隊列模型,各部分的作用。

  • 1.MessageQueue:讀取會自動刪除消息,單鏈表維護,在插入和刪除上有優勢。在其next()中會無限循環,不斷判斷是否有消息,有就返回這條消息並移除。
  • 2.Looper:Looper創建的時候會創建一個MessageQueue,調用loop()方法的時候消息循環開始,loop()也是一個死循環,會不斷調用messageQueue的next(),當有消息就處理,否則阻塞在messageQueue的next()中。當Looper的quit()被調用的時候會調用messageQueue的quit(),此時next()會返回null,然後loop()方法也跟着退出。
  • 3.Handler:在主線程構造一個Handler,然後在其他線程調用sendMessage(),此時主線程的MessageQueue中會插入一條message,然後被Looper使用。
  • 4.系統的主線程在ActivityThread的main()爲入口開啓主線程,其中定義了內部類Activity.H定義了一系列消息類型,包含四大組件的啓動停止。

13. 怎樣退出終止App:自己設置一個Activity的棧,然後一個個finish()。

14. Android IPC:Binder原理

  • 1.在Activity和Service進行通訊的時候,用到了Binder。
    • 1.當屬於同個進程我們可以繼承Binder然後在Activity中對Service進行操作
    • 2.當不屬於同個進程,那麼要用到AIDL讓系統給我們創建一個Binder,然後在Activity中對遠端的Service進行操作。
  • 2.系統給我們生成的Binder:
    • 1.Stub類中有:接口方法的id,有該Binder的標識,有asInterface(IBinder)(讓我們在Activity中獲取實現了Binder的接口,接口的實現在Service裏,同進程時候返回Stub否則返回Proxy),有onTransact()這個方法是在不同進程的時候讓Proxy在Activity進行遠端調用實現Activity操作Service
    • 2.Proxy類是代理,在Activity端,其中有:IBinder mRemote(這就是遠端的Binder),兩個接口的實現方法不過是代理最終還是要在遠端的onTransact()中進行實際操作。
  • 3.哪一端的Binder是副本,該端就可以被另一端進行操作,因爲Binder本體在定義的時候可以操作本端的東西。所以可以在Activity端傳入本端的Binder,讓Service端對其進行操作稱爲Listener,可以用RemoteCallbackList這個容器來裝Listener,防止Listener因爲經歷過序列化而產生的問題。
  • 4.當Activity端向遠端進行調用的時候,當前線程會掛起,當方法處理完畢纔會喚醒。
  • 5.如果一個AIDL就用一個Service太奢侈,所以可以使用Binder池的方式,建立一個AIDL其中的方法是返回IBinder,然後根據方法中傳入的參數返回具體的AIDL。
  • 6.IPC的方式有:Bundle(在Intent啓動的時候傳入,不過是一次性的),文件共享(對於SharedPreference是特例,因爲其在內存中會有緩存),使用Messenger(其底層用的也是AIDL,同理要操作哪端,就在哪端定義Messenger),AIDL,ContentProvider(在本進程中繼承實現一個ContentProvider,在增刪改查方法中調用本進程的SQLite,在其他進程中查詢),Socket

15.android的優化

16.一個singleton如何實現線程的同步問題

  • 1.單例類確保自己只有一個實例(構造函數私有:不被外部實例化,也不被繼承)。
  • 2.單例類必須自己創建自己的實例。
  • 3.單例類必須爲其他對象提供唯一的實例。

17.android重要術語解釋

  • 1.ActivityManagerServices,簡稱AMS,服務端對象,負責系統中所有Activity的生命週期
  • 2.ActivityThread,App的真正入口。當開啓App之後,會調用main()開始運行,開啓消息循環隊列,這就是傳說中的UI線程或者叫主線程。與ActivityManagerServices配合,一起完成Activity的管理工作
  • 3.ApplicationThread,用來實現ActivityManagerService與ActivityThread之間的交互。在ActivityManagerService需要管理相關Application中的Activity的生命週期時,通過ApplicationThread的代理對象與ActivityThread通訊。
  • 4.ApplicationThreadProxy,是ApplicationThread在服務器端的代理,負責和客戶端的ApplicationThread通訊。AMS就是通過該代理與ActivityThread進行通信的。
  • 5.Instrumentation,每一個應用程序只有一個Instrumentation對象,每個Activity內都有一個對該對象的引用。Instrumentation可以理解爲應用進程的管家,ActivityThread要創建或暫停某個Activity時,都需要通過Instrumentation來進行具體的操作。
  • 6.ActivityStack,Activity在AMS的棧管理,用來記錄已經啓動的Activity的先後關係,狀態信息等。通過ActivityStack決定是否需要啓動新的進程。
  • 7.ActivityRecord,ActivityStack的管理對象,每個Activity在AMS對應一個ActivityRecord,來記錄Activity的狀態以及其他的管理信息。其實就是服務器端的Activity對象的映像。
  • 8.TaskRecord,AMS抽象出來的一個“任務”的概念,是記錄ActivityRecord的棧,一個“Task”包含若干個ActivityRecord。AMS用TaskRecord確保Activity啓動和退出的順序。如果你清楚Activity的4種launchMode,那麼對這個概念應該不陌生。

18.理解Window和WindowManager

  • 1.Window用於顯示View和接收各種事件,Window有三種類型:應用Window(每個Activity對應一個Window)、子Window(不能單獨存在,附屬於特定Window)、系統window(Toast和狀態欄)
  • 2.Window分層級,應用Window在1-99、子Window在1000-1999、系統Window在2000-2999.WindowManager提供了增刪改View三個功能。
  • 3.Window是個抽象概念:每一個Window對應着一個View和ViewRootImpl,Window通過ViewRootImpl來和View建立聯繫,View是Window存在的實體,只能通過WindowManager來訪問Window。
  • 4.WindowManager的實現是WindowManagerImpl其再委託給WindowManagerGlobal來對Window進行操作,其中有四個List分別儲存對應的View、ViewRootImpl、WindowManger.LayoutParams和正在被刪除的View
  • 5.Window的實體是存在於遠端的WindowMangerService中,所以增刪改Window在本端是修改上面的幾個List然後通過ViewRootImpl重繪View,通過WindowSession(每個應用一個)在遠端修改Window。
  • 6.Activity創建Window:Activity會在attach()中創建Window並設置其回調(onAttachedToWindow()、dispatchTouchEvent()),Activity的Window是由Policy類創建PhoneWindow實現的。然後通過Activity#setContentView()調用PhoneWindow的setContentView。

19.Bitmap的處理:

  • 1.當使用ImageView的時候,可能圖片的像素大於ImageView,此時就可以通過BitmapFactory.Option來對圖片進行壓縮,inSampleSize表示縮小2^(inSampleSize-1)倍。
  • 2.BitMap的緩存:
    • 1.使用LruCache進行內存緩存。
    • 2.使用DiskLruCache進行硬盤緩存。
    • 3.實現一個ImageLoader的流程:同步異步加載、圖片壓縮、內存硬盤緩存、網絡拉取
      • 1.同步加載只創建一個線程然後按照順序進行圖片加載
      • 2.異步加載使用線程池,讓存在的加載任務都處於不同線程
      • 3.爲了不開啓過多的異步任務,只在列表靜止的時候開啓圖片加載

20.綜合技術:

  • 1.CrashHandler:獲取app crash的信息保存在本地然後在下一次打開app的時候發送到服務器。
  • 2.multidex解決方法數過大的問題

21.如何實現一個網絡框架(參考Volley)

  • 1.緩存隊列,以url爲key緩存內容可以參考Bitmap的處理方式,這裏單獨開啓一個線程。
  • 2.網絡請求隊列,使用線程池進行請求。
  • 3.提供各種不同類型的返回值的解析如String,Json,圖片等等。

22.ClassLoader的基礎知識:

  • 1.雙親委託:一個ClassLoader類負責加載這個類所涉及的所有類,在加載的時候會判斷該類是否已經被加載過,然後會遞歸去他父ClassLoader中找。
  • 2.可以動態加載Jar通過URLClassLoader
  • 3.ClassLoader 隔離問題 JVM識別一個類是由:ClassLoader id+PackageName+ClassName。
  • 4.加載不同Jar包中的公共類:
    • 1.讓父ClassLoader加載公共的Jar,子ClassLoader加載包含公共Jar的Jar,此時子ClassLoader在加載公共Jar的時候會先去父ClassLoader中找。(只適用Java)
    • 2.重寫加載包含公共Jar的Jar的ClassLoader,在loadClass中找到已經加載過公共Jar的ClassLoader,也就是把父ClassLoader替換掉。(只適用Java)
    • 3.在生成包含公共Jar的Jar時候把公共Jar去掉。

23.插件化框架描述:dynamicLoadApk爲例子

  • 1.可以通過DexClassLoader來對apk中的dex包進行加載訪問
  • 2.如何加載資源是個很大的問題,因爲宿主程序中並沒有apk中的資源,所以調用R資源會報錯,所以這裏使用了Activity中的實現ContextImpl的getAssets()和getResources()再加上反射來實現。
  • 3.由於系統啓動Activity有很多初始化動作要做,而我們手動反射很難完成,所以可以採用接口機制,將Activity的大部分生命週期提取成接口,然後通過代理Activity去調用插件Activity的生命週期。同時如果像增加一個新生命週期方法的時候,只需要在接口中和代理中聲明一下就行。
  • 4.缺點:
    • 1.慎用this,因爲在apk中使用this並不代表宿主中的activity,當然如果this只是表示自己的接口還是可以的。除此之外可以使用that代替this。
    • 2.不支持Service和靜態註冊的Broadcast
    • 3.不支持LaunchMode和Apk中Activity的隱式調用。

24.熱修復:Andfix爲例子

  • 1.大致原理:apkpatch將兩個apk做一次對比,然後找出不同的部分。可以看到生成的apatch了文件,後綴改成zip再解壓開,裏面有一個dex文件。通過jadx查看一下源碼,裏面就是被修復的代碼所在的類文件,這些更改過的類都加上了一個_CF的後綴,並且變動的方法都被加上了一個叫@MethodReplace的annotation,通過clazz和method指定了需要替換的方法。然後客戶端sdk得到補丁文件後就會根據annotation來尋找需要替換的方法。最後由JNI層完成方法的替換。
  • 2.無法添加新類和新的字段、補丁文件很容易被反編譯、加固平臺可能會使熱補丁功能失效
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章