2019初中級Android開發社招面試解答(上)

Android的後花園發表於2019-03-08

金三銀四,衝擊大廠,你值得擁有的一份2019初中級移動端社招面試總結+解答

注:因為實際開發與參考答案會有所不同,再者怕誤導大家,所以這些面試題答案還是自己去理解!面試官會針對簡歷中提到的知識點由淺入深提問,所以不要背答案,多理解。

2019初中級Android開發社招面試解答(上)

Android篇

Activity

1、說下Activity生命週期 ?

  • 參考解答:在正常情況下,Activity的常用生命週期就只有如下7個
    • onCreate():表示Activity正在被建立,常用來初始化工作,比如呼叫setContentView載入介面佈局資源,初始化Activity所需資料等;
    • onRestart():表示Activity正在重新啟動,一般情況下,當前Acitivty從不可見重新變為可見時,OnRestart就會被呼叫;
    • onStart():表示Activity正在被啟動,此時Activity可見但不在前臺,還處於後臺,無法與使用者互動;
    • onResume():表示Activity獲得焦點,此時Activity可見且在前臺並開始活動,這是與onStart的區別所在;
    • onPause():表示Activity正在停止,此時可做一些儲存資料、停止動畫等工作,但是不能太耗時,因為這會影響到新Activity的顯示,onPause必須先執行完,新Activity的onResume才會執行;
    • onStop():表示Activity即將停止,可以做一些稍微重量級的回收工作,比如登出廣播接收器、關閉網路連線等,同樣不能太耗時;
    • onDestroy():表示Activity即將被銷燬,這是Activity生命週期中的最後一個回撥,常做回收工作、資源釋放
  • 延伸:從整個生命週期來看,onCreate和onDestroy是配對的,分別標識著Activity的建立和銷燬,並且只可能有一次呼叫; 從Activity是否可見來說,onStart和onStop是配對的,這兩個方法可能被呼叫多次; 從Activity是否在前臺來說,onResume和onPause是配對的,這兩個方法可能被呼叫多次; 除了這種區別,在實際使用中沒有其他明顯區別;

2、Activity A 啟動另一個Activity B 會呼叫哪些方法?如果B是透明主題的又或則是個DialogActivity呢 ?

  • 參考解答:Activity A 啟動另一個Activity B,回撥如下
    • Activity A 的onPause() → Activity B的onCreate() → onStart() → onResume() → Activity A的onStop();
    • 如果B是透明主題又或則是個DialogActivity,則不會回撥A的onStop;

3、說下onSaveInstanceState()方法的作用 ? 何時會被呼叫?

  • 參考解答:發生條件:異常情況下(系統配置發生改變時導致Activity被殺死並重新建立、資源記憶體不足導致低優先順序的Activity被殺死
    • 系統會呼叫onSaveInstanceState來儲存當前Activity的狀態,此方法呼叫在onStop之前,與onPause沒有既定的時序關係;
    • 當Activity被重建後,系統會呼叫onRestoreInstanceState,並且把onSave(簡稱)方法所儲存的Bundle物件同時傳參給onRestore(簡稱)和onCreate(),因此可以通過這兩個方法判斷Activity是否被重建,呼叫在onStart之後;
      異常情況下Activity的重建過程

4、說下 Activity的四種啟動模式、應用場景 ?

  • 參考回答:
    • standard標準模式:每次啟動一個Activity都會重新建立一個新的例項,不管這個例項是否已經存在,此模式的Activity預設會進入啟動它的Activity所屬的任務棧中;
    • singleTop棧頂複用模式:如果新Activity已經位於任務棧的棧頂,那麼此Activity不會被重新建立,同時會回撥onNewIntent方法,如果新Activity例項已經存在但不在棧頂,那麼Activity依然會被重新建立;
    • singleTask棧內複用模式:只要Activity在一個任務棧中存在,那麼多次啟動此Activity都不會重新建立例項,並回撥onNewIntent方法,此模式啟動Activity A,系統首先會尋找是否存在A想要的任務棧,如果不存在,就會重新建立一個任務棧,然後把建立好A的例項放到棧中;
    • singleInstance單例項模式:這是一種加強的singleTask模式,具有此種模式的Activity只能單獨地位於一個任務棧中,且此任務棧中只有唯一一個例項;

5、瞭解哪些Activity常用的標記位Flags?

  • FLAG_ACTIVITY_NEW_TASK : 對應singleTask啟動模式,其效果和在XML中指定該啟動模式相同;
  • FLAG_ACTIVITY_SINGLE_TOP : 對應singleTop啟動模式,其效果和在XML中指定該啟動模式相同;
  • FLAG_ACTIVITY_CLEAR_TOP : 具有此標記位的Activity,當它啟動時,在同一個任務棧中所有位於它上面的Activity都要出棧。這個標記位一般會和singleTask模式一起出現,在這種情況下,被啟動Activity的例項如果已經存在,那麼系統就會回撥onNewIntent。如果被啟動的Activity採用standard模式啟動,那麼它以及連同它之上的Activity都要出棧,系統會建立新的Activity例項並放入棧中;
  • FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS : 具有這個標記的 Activity 不會出現在歷史 Activity 列表中;

6、說下 Activity跟window,view之間的關係?

  • 參考回答:
    • Activity 建立時通過attach()初始化了一個 Window 也就是 PhoneWindow,一個 PhoneWindow 持有一個 DecorView 的例項,DecorView 本身是一個 FrameLayout,繼承於View,Activty通過setContentView將xml佈局控制元件不斷addView()新增到View中,最終顯示到Window於我們互動;
    • 推薦文章: Activity、View、Window的理解一篇文章就夠了

7、橫豎屏切換的Activity生命週期變化?

  • 參考回答:
    • 不設定Activity的android:configChanges時,切屏會銷燬當前Activity,然後重新載入呼叫各個生命週期,切橫屏時會執行一次,切豎屏時會執行兩次; onPause() →onStop()→onDestory()→onCreate()→onStart()→onResume()
    • 設定Activity的android:configChanges="orientation"時,切屏還是會重新呼叫各個生命週期,切橫、豎屏時只會執行一次;
    • 設定Activity的android:configChanges="orientation|keyboardHidden|screenSize"時,切屏不會重新呼叫各個生命週期,只會執行onConfigurationChanged方法;
    • 推薦文章: Android 橫豎屏切換載入不同的佈局

8、如何啟動其他應用的Activity?

  • 參考回答:
    • 在保證有許可權訪問的情況下,通過隱式Intent進行目標Activity的IntentFilter匹配,原則是:
      • 一個intent只有同時匹配某個Activity的intent-filter中的action、category、data才算完全匹配,才能啟動該Activity;
      • 一個Activity可以有多個 intent-filter,一個 intent只要成功匹配任意一組 intent-filter,就可以啟動該Activity;
    • 推薦文章: action、category、data的具體匹配規則

9、Activity的啟動過程?(重點)

  • 參考回答:
    • 點選App圖示後通過startActivity遠端呼叫到AMS中,AMS中將新啟動的activity以activityrecord的結構壓入activity棧中,並通過遠端binder回撥到原程式,使得原程式進入pause狀態,原程式pause後通知AMS我pause了
    • 此時AMS再根據棧中Activity的啟動intent中的flag是否含有new_task的標籤判斷是否需要啟動新程式,啟動新程式通過startProcessXXX的函式
    • 啟動新程式後通過反射呼叫ActivityThread的main函式,main函式中呼叫looper.prepar和lopper.loop啟動訊息佇列迴圈機制。最後遠端告知AMS我啟動了。AMS回撥handleLauncherAcitivyt載入activity。在handlerLauncherActivity中會通過反射呼叫Application的onCreate和activity的onCreate以及通過handleResumeActivity中反射呼叫Activity的onResume
      2019初中級Android開發社招面試解答(上)
  • 推薦文章: Android四大元件啟動機制之Activity啟動過程

Fragment

1、談一談Fragment的生命週期?

  • 參考回答:
    • Fragment從建立到銷燬整個生命週期中涉及到的方法依次為:onAttach()→onCreate()→ onCreateView()→onActivityCreated()→onStart()→onResume()→onPause()→onStop()→onDestroyView()→onDestroy()→onDetach(),其中和Activity有不少名稱相同作用相似的方法,而不同的方法有:
      • onAttach():當Fragment和Activity建立關聯時呼叫;
      • onCreateView():當fragment建立檢視呼叫,在onCreate之後;
      • onActivityCreated():當與Fragment相關聯的Activity完成onCreate()之後呼叫;
      • onDestroyView():在Fragment中的佈局被移除時呼叫;
      • onDetach():當Fragment和Activity解除關聯時呼叫;
  • 推薦文章:Android之Fragment優點

2、談談Activity和Fragment的區別?

  • 參考回答:
    • 相似點:都可包含佈局、可有自己的生命週期
    • 不同點:
      • Fragment相比較於Activity多出4個回撥週期,在控制操作上更靈活;
      • Fragment可以在XML檔案中直接進行寫入,也可以在Activity中動態新增;
      • Fragment可以使用show()/hide()或者replace()隨時對Fragment進行切換,並且切換的時候不會出現明顯的效果,使用者體驗會好;Activity雖然也可以進行切換,但是Activity之間切換會有明顯的翻頁或者其他的效果,在小部分內容的切換上給使用者的感覺不是很好;

3、Fragment中add與replace的區別(Fragment重疊)

  • 參考回答:
    • add不會重新初始化fragment,replace每次都會。所以如果在fragment生命週期內獲取獲取資料,使用replace會重複獲取;
    • 新增相同的fragment時,replace不會有任何變化,add會報IllegalStateException異常;
    • replace先remove掉相同id的所有fragment,然後在add當前的這個fragment,而add是覆蓋前一個fragment。所以如果使用add一般會伴隨hide()和show(),避免佈局重疊;
    • 使用add,如果應用放在後臺,或以其他方式被系統銷燬,再開啟時,hide()中引用的fragment會銷燬,所以依然會出現佈局重疊bug,可以使用replace或使用add時,新增一個tag引數;
      2019初中級Android開發社招面試解答(上)

4、getFragmentManager、getSupportFragmentManager 、getChildFragmentManager之間的區別?

  • 參考回答:
    • getFragmentManager()所得到的是所在fragment 的父容器的管理器, getChildFragmentManager()所得到的是在fragment 裡面子容器的管理器, 如果是fragment巢狀fragment,那麼就需要利用getChildFragmentManager();
    • 因為Fragment是3.0 Android系統API版本才出現的元件,所以3.0以上系統可以直接呼叫getFragmentManager()來獲取FragmentManager()物件,而3.0以下則需要呼叫getSupportFragmentManager() 來間接獲取;

5、FragmentPagerAdapter與FragmentStatePagerAdapter的區別與使用場景

  • 參考回答:
    • 相同點 :二者都繼承PagerAdapter
    • 不同點 :FragmentPagerAdapter的每個Fragment會持久的儲存在FragmentManager中,只要使用者可以返回到頁面中,它都不會被銷燬。因此適用於那些資料相對靜態的頁,Fragment數量也比較少的那種; FragmentStatePagerAdapter只保留當前頁面,當頁面不可見時,該Fragment就會被消除,釋放其資源。因此適用於那些資料動態性較大、佔用記憶體較多,多Fragment的情況;

Service

1、談一談Service的生命週期?

  • 參考回答:Service的生命週期涉及到六大方法
    • onCreate():如果service沒被建立過,呼叫startService()後會執行onCreate()回撥;如果service已處於執行中,呼叫startService()不會執行onCreate()方法。也就是說,onCreate()只會在第一次建立service時候呼叫,多次執行startService()不會重複呼叫onCreate(),此方法適合完成一些初始化工作;
    • onStartComand():服務啟動時呼叫,此方法適合完成一些資料載入工作,比如會在此處建立一個執行緒用於下載資料或播放音樂;
    • onBind():服務被繫結時呼叫;
    • onUnBind():服務被解綁時呼叫;
    • onDestroy():服務停止時呼叫;
  • 推薦文章: Android元件系列----Android Service元件深入解析

2、Service的兩種啟動方式?區別在哪?

  • 參考回答:Service的兩種啟動模式
    • startService():通過這種方式呼叫startService,onCreate()只會被呼叫一次,多次呼叫startSercie會多次執行onStartCommand()和onStart()方法。如果外部沒有呼叫stopService()或stopSelf()方法,service會一直執行。
    • bindService():如果該服務之前還沒建立,系統回撥順序為onCreate()→onBind()。如果呼叫bindService()方法前服務已經被繫結,多次呼叫bindService()方法不會多次建立服務及繫結。如果呼叫者希望與正在繫結的服務解除繫結,可以呼叫unbindService()方法,回撥順序為onUnbind()→onDestroy();
      2019初中級Android開發社招面試解答(上)
  • 推薦文章: Android Service兩種啟動方式詳解

3、如何保證Service不被殺死 ?

  • 參考回答:
    • onStartCommand方式中,返回START_STICKY或則START_REDELIVER_INTENT
      • START_STICKY:如果返回START_STICKY,表示Service執行的程式被Android系統強制殺掉之後,Android系統會將該Service依然設定為started狀態(即執行狀態),但是不再儲存onStartCommand方法傳入的intent物件
      • START_NOT_STICKY:如果返回START_NOT_STICKY,表示當Service執行的程式被Android系統強制殺掉之後,不會重新建立該Service
      • START_REDELIVER_INTENT:如果返回START_REDELIVER_INTENT,其返回情況與START_STICKY類似,但不同的是系統會保留最後一次傳入onStartCommand方法中的Intent再次保留下來並再次傳入到重新建立後的Service的onStartCommand方法中
    • 提高Service的優先順序 在AndroidManifest.xml檔案中對於intent-filter可以通過android:priority = "1000"這個屬性設定最高優先順序,1000是最高值,如果數字越小則優先順序越低,同時適用於廣播;
    • 在onDestroy方法裡重啟Service 當service走到onDestroy()時,傳送一個自定義廣播,當收到廣播時,重新啟動service;
    • 提升Service程式的優先順序 程式優先順序由高到低:前臺程式 一 可視程式 一 服務程式 一 後臺程式 一 空程式 可以使用startForeground將service放到前臺狀態,這樣低記憶體時,被殺死的概率會低一些;
    • 系統廣播監聽Service狀態
    • 將APK安裝到/system/app,變身為系統級應用
  • 注意:以上機制都不能百分百保證Service不被殺死,除非做到系統白名單,與系統同生共死

4、能否在Service開啟耗時操作 ? 怎麼做 ?

  • 參考回答:
    • Service預設並不會執行在子執行緒中,也不執行在一個獨立的程式中,它同樣執行在主執行緒中(UI執行緒)。換句話說,不要在Service裡執行耗時操作,除非手動開啟一個子執行緒,否則有可能出現主執行緒被阻塞(ANR)的情況;

5、用過哪些系統Service ?

  • 參考回答:
    2019初中級Android開發社招面試解答(上)

6、瞭解ActivityManagerService嗎?發揮什麼作用

  • 參考回答: ActivityManagerService是Android中最核心的服務 , 主要負責系統中四大元件的啟動、切換、排程及應用程式的管理和排程等工作,其職責與作業系統中的程式管理和排程模組類似;
  • 推薦文章: ActivityManagerService分析——AMS啟動流程

Broadcast Receiver

1、廣播有幾種形式 ? 都有什麼特點 ?

  • 參考回答:
    • 普通廣播:開發者自身定義 intent的廣播(最常用),所有的廣播接收器幾乎會在同一時刻接受到此廣播資訊,接受的先後順序隨機
    • 有序廣播:傳送出去的廣播被廣播接收者按照先後順序接收,同一時刻只會有一個廣播接收器能夠收到這條廣播訊息,當這個廣播接收器中的邏輯執行完畢後,廣播才會繼續傳遞,且優先順序(priority)高的廣播接收器會先收到廣播訊息。有序廣播可以被接收器截斷使得後面的接收器無法收到它;
    • 本地廣播:僅在自己的應用內傳送接收廣播,也就是隻有自己的應用能收到,資料更加安全,效率更高,但只能採用動態註冊的方式;
    • 粘性廣播:這種廣播會一直滯留,當有匹配該廣播的接收器被註冊後,該接收器就會收到此條廣播;
  • 推薦文章: Android四大元件:BroadcastReceiver史上最全面解析

2、廣播的兩種註冊方式 ?

  • 參考回答:
    2019初中級Android開發社招面試解答(上)

3、廣播傳送和接收的原理了解嗎 ?(Binder機制、AMS)

ContentProvider

1、ContentProvider瞭解多少?

  • 參考回答: ContentProvider作為四大元件之一,其主要負責儲存和共享資料。與檔案儲存、SharedPreferences儲存、SQLite資料庫儲存這幾種資料儲存方法不同的是,後者儲存下的資料只能被該應用程式使用,而前者可以讓不同應用程式之間進行資料共享,它還可以選擇只對哪一部分資料進行共享,從而保證程式中的隱私資料不會有洩漏風險。
  • 推薦文章: Android:關於ContentProvider的知識都在這裡了!

2、ContentProvider的許可權管理?

  • 參考回答:
    • 讀寫分離
    • 許可權控制-精確到表級
    • URL控制

3、說說ContentProvider、ContentResolver、ContentObserver 之間的關係?

  • 參考回答:
    • ContentProvider:管理資料,提供資料的增刪改查操作,資料來源可以是資料庫、檔案、XML、網路等,ContentProvider為這些資料的訪問提供了統一的介面,可以用來做程式間資料共享。
    • ContentResolver:ContentResolver可以為不同URI操作不同的ContentProvider中的資料,外部程式可以通過ContentResolver與ContentProvider進行互動。
    • ContentObserver:觀察ContentProvider中的資料變化,並將變化通知給外界。

資料儲存

1、描述一下Android資料持久儲存方式?

  • 參考回答:Android平臺實現資料持久儲存的常見幾種方式:
    • SharedPreferences儲存:一種輕型的資料儲存方式,本質是基於XML檔案儲存的key-value鍵值對資料,通常用來儲存一些簡單的配置資訊(如應用程式的各種配置資訊);
    • SQLite資料庫儲存:一種輕量級嵌入式資料庫引擎,它的運算速度非常快,佔用資源很少,常用來儲存大量複雜的關係資料;
    • ContentProvider:四大元件之一,用於資料的儲存和共享,不僅可以讓不同應用程式之間進行資料共享,還可以選擇只對哪一部分資料進行共享,可保證程式中的隱私資料不會有洩漏風險;
    • File檔案儲存:寫入和讀取檔案的方法和 Java中實現I/O的程式一樣;
    • 網路儲存:主要在遠端的伺服器中儲存相關資料,使用者操作的相關資料可以同步到伺服器上;

2、SharedPreferences的應用場景?注意事項?

  • 參考回答:
    • SharedPreferences是一種輕型的資料儲存方式,本質是基於XML檔案儲存的key-value鍵值對資料,通常用來儲存一些簡單的配置資訊,如int,String,boolean、float和long;
    • 注意事項:
      • 勿儲存大型複雜資料,這會引起記憶體GC、阻塞主執行緒使頁面卡頓產生ANR
      • 勿在多程式模式下,操作Sp
      • 不要多次edit和apply,儘量批量修改一次提交
      • 建議apply,少用commit

3、SharedPrefrences的apply和commit有什麼區別?

  • 參考回答:
  • apply沒有返回值而commit返回boolean表明修改是否提交成功。
  • apply是將修改資料原子提交到記憶體, 而後非同步真正提交到硬體磁碟, 而commit是同步的提交到硬體磁碟,因此,在多個併發的提交commit的時候,他們會等待正在處理的commit儲存到磁碟後在操作,從而降低了效率。而apply只是原子的提交到內容,後面有呼叫apply的函式的將會直接覆蓋前面的記憶體資料,這樣從一定程度上提高了很多效率。
  • apply方法不會提示任何失敗的提示。 由於在一個程式中,sharedPreference是單例項,一般不會出現併發衝突,如果對提交的結果不關心的話,建議使用apply,當然需要確保提交成功且有後續操作的話,還是需要用commit的。

4、瞭解SQLite中的事務操作嗎?是如何做的

  • 參考回答:
    • SQLite在做CRDU操作時都預設開啟了事務,然後把SQL語句翻譯成對應的SQLiteStatement並呼叫其相應的CRUD方法,此時整個操作還是在rollback journal這個臨時檔案上進行,只有操作順利完成才會更新db資料庫,否則會被回滾;

5、使用SQLite做批量操作有什麼好的方法嗎?

  • 參考回答:
    • 使用SQLiteDatabase的beginTransaction方法開啟一個事務,將批量操作SQL語句轉化為SQLiteStatement並進行批量操作,結束後endTransaction()

6、如何刪除SQLite中表的個別欄位

  • 參考回答:
    • SQLite資料庫只允許增加欄位而不允許修改和刪除表欄位,只能建立新表保留原有欄位,刪除原表

7、使用SQLite時會有哪些優化操作?

  • 參考回答:
    • 使用事務做批量操作
    • 及時關閉Cursor,避免記憶體洩露
    • 耗時操作非同步化:資料庫的操作屬於本地IO耗時操作,建議放入非同步執行緒中處理
    • ContentValues的容量調整:ContentValues內部採用HashMap來儲存Key-Value資料,ContentValues初始容量為8,擴容時翻倍。因此建議對ContentValues填入的內容進行估量,設定合理的初始化容量,減少不必要的內部擴容操作
    • 使用索引加快檢索速度:對於查詢操作量級較大、業務對查詢要求較高的推薦使用索引

IPC

1、Android中程式和執行緒的關係? 區別?

  • 參考回答:
    • 執行緒是CPU排程的最小單元,同時執行緒是一種有限的系統資源
    • 程式一般指一個執行單元,在PC和移動裝置上一個程式或則一個應用
    • 一般來說,一個App程式至少有一個程式,一個程式至少有一個執行緒(包含與被包含的關係), 通俗來講就是,在App這個工廠裡面有一個程式,執行緒就是裡面的生產線,但主執行緒(主生產線)只有一條,而子執行緒(副生產線)可以有多個
    • 程式有自己獨立的地址空間,而程式中的執行緒共享此地址空間,都可以併發執行
  • 推薦文章: Android developer官方文件--程式和執行緒

2、如何開啟多程式 ? 應用是否可以開啟N個程式 ?

3、為何需要IPC?多程式通訊可能會出現的問題?

  • 參考回答:
    • 所有執行在不同程式的四大元件(Activity、Service、Receiver、ContentProvider)共享資料都會失敗,這是由於Android為每個應用分配了獨立的虛擬機器,不同的虛擬機器在記憶體分配上有不同的地址空間,這會導致在不同的虛擬機器中訪問同一個類的物件會產生多份副本。比如常用例子(通過開啟多程式獲取更大記憶體空間、兩個或則多個應用之間共享資料、微信全家桶
    • 一般來說,使用多程式通訊會造成如下幾方面的問題
      • 靜態成員和單例模式完全失效:獨立的虛擬機器造成
      • 執行緒同步機制完全實效:獨立的虛擬機器造成
      • SharedPreferences的可靠性下降:這是因為Sp不支援兩個程式併發進行讀寫,有一定機率導致資料丟失
      • Application會多次建立:Android系統在建立新的程式會分配獨立的虛擬機器,所以這個過程其實就是啟動一個應用的過程,自然也會建立新的Application
  • 推薦文章: Android developer官方文件--程式和執行緒

4、Android中IPC方式、各種方式優缺點,為什麼選擇Binder?

  • 參考回答:
    2019初中級Android開發社招面試解答(上)
    與Linux上傳統的IPC機制,比如System V,Socket相比,Binder好在哪呢?
    • 傳輸效率高、可操作性強:傳輸效率主要影響因素是記憶體拷貝的次數,拷貝次數越少,傳輸速率越高。從Android程式架構角度分析:對於訊息佇列、Socket和管道來說,資料先從傳送方的快取區拷貝到核心開闢的快取區中,再從核心快取區拷貝到接收方的快取區,一共兩次拷貝,如圖:
      2019初中級Android開發社招面試解答(上)
      而對於Binder來說,資料從傳送方的快取區拷貝到核心的快取區,而接收方的快取區與核心的快取區是對映到同一塊實體地址的,節省了一次資料拷貝的過程,如圖:
      2019初中級Android開發社招面試解答(上)
      由於共享記憶體操作複雜,綜合來看,Binder的傳輸效率是最好的。
    • 實現C/S架構方便:Linux的眾IPC方式除了Socket以外都不是基於C/S架構,而Socket主要用於網路間的通訊且傳輸效率較低。Binder基於C/S架構 ,Server端與Client端相對獨立,穩定性較好。
    • 安全性高:傳統Linux IPC的接收方無法獲得對方程式可靠的UID/PID,從而無法鑑別對方身份;而Binder機制為每個程式分配了UID/PID且在Binder通訊時會根據UID/PID進行有效性檢測。
  • 推薦文章: 為什麼 Android 要採用 Binder 作為 IPC 機制?

5、Binder機制的作用和原理?

  • 參考回答:
    • Linux系統將一個程式分為使用者空間核心空間。對於程式之間來說,使用者空間的資料不可共享,核心空間的資料可共享,為了保證安全性和獨立性,一個程式不能直接操作或者訪問另一個程式,即Android的程式是相互獨立、隔離的,這就需要跨程式之間的資料通訊方式
      傳統IPC機制原理
  • 一次完整的 Binder IPC 通訊過程通常是這樣:
    • 首先 Binder 驅動在核心空間建立一個資料接收快取區;
    • 接著在核心空間開闢一塊核心快取區,建立核心快取區和核心中資料接收快取區之間的對映關係,以及核心中資料接收快取區和接收程式使用者空間地址的對映關係;
    • 傳送方程式通過系統呼叫 copyfromuser() 將資料 copy 到核心中的核心快取區,由於核心快取區和接收程式的使用者空間存在記憶體對映,因此也就相當於把資料傳送到了接收程式的使用者空間,這樣便完成了一次程式間的通訊。
      Binder機制原理

6、Binder框架中ServiceManager的作用?

  • 參考回答:
    • Binder框架 是基於 C/S 架構的。由一系列的元件組成,包括 Client、Server、ServiceManager、Binder驅動,其中 Client、Server、Service Manager 執行在使用者空間,Binder 驅動執行在核心空間
      2019初中級Android開發社招面試解答(上)
      • Server&Client:伺服器&客戶端。在Binder驅動和Service Manager提供的基礎設施上,進行Client-Server之間的通訊。
      • ServiceManager(如同DNS域名伺服器)服務的管理者,將Binder名字轉換為Client中對該Binder的引用,使得Client可以通過Binder名字獲得Server中Binder實體的引用。
      • Binder驅動(如同路由器):負責程式之間binder通訊的建立,傳遞,計數管理以及資料的傳遞互動等底層支援。
        2019初中級Android開發社招面試解答(上)
        圖片出自Carson_Ho文章 —— Android跨程式通訊:圖文詳解 Binder機制 原理

7、Bundle傳遞物件為什麼需要序列化?Serialzable和Parcelable的區別?

  • 參考回答:
    • 因為bundle傳遞資料時只支援基本資料型別,所以在傳遞物件時需要序列化轉換成可儲存或可傳輸的本質狀態(位元組流)。序列化後的物件可以在網路、IPC(比如啟動另一個程式的Activity、Service和Reciver)之間進行傳輸,也可以儲存到本地。
    • 序列化實現的兩種方式:實現Serializable/Parcelable介面。不同點如圖:
      2019初中級Android開發社招面試解答(上)

8、講講AIDL?原理是什麼?如何優化多模組都使用AIDL的情況?

  • 參考回答:
    • AIDL(Android Interface Definition Language,Android介面定義語言):如果在一個程式中要呼叫另一個程式中物件的方法,可使用AIDL生成可序列化的引數,AIDL會生成一個服務端物件的代理類,通過它客戶端實現間接呼叫服務端物件的方法。
    • AIDL的本質是系統提供了一套可快速實現Binder的工具。關鍵類和方法:
      • AIDL介面:繼承IInterface。
      • Stub類:Binder的實現類,服務端通過這個類來提供服務。
      • Proxy類:伺服器的本地代理,客戶端通過這個類呼叫伺服器的方法。
      • asInterface():客戶端呼叫,將服務端的返回的Binder物件,轉換成客戶端所需要的AIDL介面型別物件。如果客戶端和服務端位於統一程式,則直接返回Stub物件本身,否則返回系統封裝後的Stub.proxy物件
      • asBinder():根據當前呼叫情況返回代理Proxy的Binder物件。
      • onTransact():執行服務端的Binder執行緒池中,當客戶端發起跨程式請求時,遠端請求會通過系統底層封裝後交由此方法來處理。
      • transact():執行在客戶端,當客戶端發起遠端請求的同時將當前執行緒掛起。之後呼叫服務端的onTransact()直到遠端請求返回,當前執行緒才繼續執行。
    • 當有多個業務模組都需要AIDL來進行IPC,此時需要為每個模組建立特定的aidl檔案,那麼相應的Service就會很多。必然會出現系統資源耗費嚴重、應用過度重量級的問題。解決辦法是建立Binder連線池,即將每個業務模組的Binder請求統一轉發到一個遠端Service中去執行,從而避免重複建立Service。
      • 工作原理:每個業務模組建立自己的AIDL介面並實現此介面,然後向服務端提供自己的唯一標識和其對應的Binder物件。服務端只需要一個Service,伺服器提供一個queryBinder介面,它會根據業務模組的特徵來返回相應的Binder物件,不同的業務模組拿到所需的Binder物件後就可進行遠端方法的呼叫了

View

1、講下View的繪製流程?

  • 參考回答:
    • View的工作流程主要是指measure、layout、draw這三大流程,即測量、佈局和繪製,其中measure確定View的測量寬/高,layout確定View的最終寬/高四個頂點的位置,而draw則將View繪製到螢幕
    • View的繪製過程遵循如下幾步:
      • 繪製背景 background.draw(canvas)
      • 繪製自己(onDraw)
      • 繪製 children(dispatchDraw)
      • 繪製裝飾(onDrawScollBars)
        2019初中級Android開發社招面試解答(上)
    • 推薦文章:

2、MotionEvent是什麼?包含幾種事件?什麼條件下會產生?

  • 參考回答:
    • MotionEvent是手指接觸螢幕後所產生的一系列事件。典型的事件型別有如下:
      • ACTION_DOWN:手指剛接觸螢幕
      • ACTION_MOVE:手指在螢幕上移動
      • ACTION_UP:手指從螢幕上鬆開的一瞬間
      • ACTION_CANCELL:手指保持按下操作,並從當前控制元件轉移到外層控制元件時觸發
    • 正常情況下,一次手指觸控螢幕的行為會觸發一系列點選事件,考慮如下幾種情況:
      • 點選螢幕後鬆開,事件序列:DOWN→UP
      • 點選螢幕滑動一會再鬆開,事件序列為DOWN→MOVE→.....→MOVE→UP

3、描述一下View事件傳遞分發機制?

  • 參考回答:
    • View事件分發本質就是對MotionEvent事件分發的過程。即當一個MotionEvent發生後,系統將這個點選事件傳遞到一個具體的View上
    • 點選事件的傳遞順序:Activity(Window)→ViewGroup→ View
    • 事件分發過程由三個方法共同完成:
      • dispatchTouchEvent:用來進行事件的分發。如果事件能夠傳遞給當前View,那麼此方法一定會被呼叫,返回結果受當前View的onTouchEvent和下級View的dispatchTouchEvent方法的影響,表示是否消耗當前事件
      • onInterceptTouchEvent:在上述方法內部呼叫,對事件進行攔截。該方法只在ViewGroup中有,View(不包含 ViewGroup)是沒有的。一旦攔截,則執行ViewGroup的onTouchEvent,在ViewGroup中處理事件,而不接著分發給View。且只呼叫一次,返回結果表示是否攔截當前事件
      • onTouchEvent: 在dispatchTouchEvent方法中呼叫,用來處理點選事件,返回結果表示是否消耗當前事件

4、如何解決View的事件衝突 ? 舉個開發中遇到的例子 ?

  • 參考回答:
    • 常見開發中事件衝突的有ScrollView與RecyclerView的滑動衝突、RecyclerView內嵌同時滑動同一方向
    • 滑動衝突的處理規則:
      • 對於由於外部滑動和內部滑動方向不一致導致的滑動衝突,可以根據滑動的方向判斷誰來攔截事件。
      • 對於由於外部滑動方向和內部滑動方向一致導致的滑動衝突,可以根據業務需求,規定何時讓外部View攔截事件,何時由內部View攔截事件。
      • 對於上面兩種情況的巢狀,相對複雜,可同樣根據需求在業務上找到突破點。
    • 滑動衝突的實現方法:
      • 外部攔截法:指點選事件都先經過父容器的攔截處理,如果父容器需要此事件就攔截,否則就不攔截。具體方法:需要重寫父容器的onInterceptTouchEvent方法,在內部做出相應的攔截。
      • 內部攔截法:指父容器不攔截任何事件,而將所有的事件都傳遞給子容器,如果子容器需要此事件就直接消耗,否則就交由父容器進行處理。具體方法:需要配合requestDisallowInterceptTouchEvent方法。

5、scrollTo()和scollBy()的區別?

  • 參考回答:
    • scollBy內部呼叫了scrollTo,它是基於當前位置的相對滑動;而scrollTo是絕對滑動,因此如果使用相同輸入引數多次呼叫scrollTo方法,由於View的初始位置是不變的,所以只會出現一次View滾動的效果
    • 兩者都只能對View內容的滑動,而非使View本身滑動。可以使用Scroller有過度滑動的效果
  • 推薦文章: View 的滑動原理和實現方式

6、Scroller是怎麼實現View的彈性滑動?

  • 參考回答:
    • 在MotionEvent.ACTION_UP事件觸發時呼叫startScroll()方法,該方法並沒有進行實際的滑動操作,而是記錄滑動相關量(滑動距離、滑動時間)
    • 接著呼叫invalidate/postInvalidate()方法,請求View重繪,導致View.draw方法被執行
    • 當View重繪後會在draw方法中呼叫computeScroll方法,而computeScroll又會去向Scroller獲取當前的scrollX和scrollY;然後通過scrollTo方法實現滑動;接著又呼叫postInvalidate方法來進行第二次重繪,和之前流程一樣,如此反覆導致View不斷進行小幅度的滑動,而多次的小幅度滑動就組成了彈性滑動,直到整個滑動過成結束
      2019初中級Android開發社招面試解答(上)

7、 invalidate()和postInvalidate()的區別 ?

  • 參考回答:
    • invalidate()與postInvalidate()都用於重新整理View,主要區別是invalidate()在主執行緒中呼叫,若在子執行緒中使用需要配合handler;而postInvalidate()可在子執行緒中直接呼叫。

8、SurfaceView和View的區別?

  • 參考回答:
    • View需要在UI執行緒對畫面進行重新整理,而SurfaceView可在子執行緒進行頁面的重新整理
    • View適用於主動更新的情況,而SurfaceView適用於被動更新,如頻繁重新整理,這是因為如果使用View頻繁重新整理會阻塞主執行緒,導致介面卡頓
    • SurfaceView在底層已實現雙緩衝機制,而View沒有,因此SurfaceView更適用於需要頻繁重新整理、重新整理時資料處理量很大的頁面(如視訊播放介面)

9、自定義View如何考慮機型適配 ?

  • 參考回答:
    • 合理使用warp_content,match_parent
    • 儘可能的是使用RelativeLayout
    • 針對不同的機型,使用不同的佈局檔案放在對應的目錄下,android會自動匹配。
    • 儘量使用點9圖片。
    • 使用與密度無關的畫素單位dp,sp
    • 引入android的百分比佈局。
    • 切圖的時候切大解析度的圖,應用到佈局當中。在小解析度的手機上也會有很好的顯示效果。

2019初中級Android開發社招面試解答(中)

相關文章