Android 面試基礎篇

本文是Android面試題整理中的一篇,結合右下角目錄食用更佳,包括:html

  • 架構
  • Activity
  • Service
  • BroadCast
  • ContentProvider
  • Fragment

架構


Android的大致架構圖

分爲四個層次:linux內核;libraies和Android runntime;framework;Application java

Android的四大組件是哪些,它們的做用?

  1. Activity:Activity是Android程序與用戶交互的窗口,對用戶來講是可見的
  2. service:後臺服務於Activity,是一個服務,不可見
  3. Content Provider:對外提提供數據
  4. BroadCast Receiver:接受一種或者多種Intent做觸發事件,接受相關消息,作一些簡單處理

Android 中進程的優先級

  1. 前臺進程
  2. 可見進程
  3. 服務進程
  4. 後臺進程
  5. 空進程

Android中asset和res目錄的區別

  1. res目錄下的資源文件會在R文件中生成對應的id,asset不會\
  2. res目錄下的文件在生成apk時,除raw(即res/raw)目錄下文件不進行編譯外,都會被編譯成二進制文件;asset目錄下的文件不會進行編譯
  3. asset目錄容許有子目錄

Android中App 是如何沙箱化的,爲什麼要這麼作

  1. 沙箱化能夠提高安全性和效率
  2. Android的底層內核爲Linux,所以繼承了Linux良好的安全性,並對其進行了優化。在Linux中,一個用戶對應一個uid,而在Android中,(一般)一個APP對應一個uid,擁有獨立的資源和空間,與其餘APP互不干擾。若有兩個APP A和B,A並不能訪問B的資源,A的崩潰也不會對B形成影響,從而保證了安全性和效率

Activity


Activity 生命週期

Activity在屏幕旋轉時的生命週期

  1. 沒有任何設置時,會調用整個生命週期方法,而且會調用onSaveInstance和onRestoreInstanceState方法
  2. 在Manifest中爲Activity設置android:configChanges="orientation"時,只調用onConfigChanges方法
  3. android:configChanges="orientation"屬性有可能不起做用,依然會調用整個生命週期方法,這是由於不一樣版本處理方式可能不一樣,有時候還須要加上android:configChanges="orientation|keyboardHidden|screenSize"等。

onSaveInstanceState 何時調用

  1. 非用戶主動明確結束(按back鍵,自定義click方法調用finish)時都會調用onSaveInstanceState:
    1. 屏幕旋轉
    2. 按HOME鍵
    3. 內存不足
    4. 從一個activity啓動另外一個activity
  2. 這個方法的調用時機是在onStop前,可是它和onPause沒有既定的時序關係

自定義View控件的狀態被保存須要知足兩個條件

  1. View有惟一的ID
  2. View的初始化時要調用setSaveEnabled(true)

configChanges屬性

對Activity配置了android:configChanges="xxx"屬性以後,Activity就不會在對應變化發生時從新建立,而是調用Activity的onConfigurationChanged方法。經常使用的有local:設備的本地位置發生了變化,通常指切換了系統語言;keyboardHidden:鍵盤的可訪問性發生了變化,好比用戶調出了鍵盤;orientation:屏幕方向發生了變化,好比旋轉了手機屏幕。linux

A activity啓動B activity和B activity返回A activity的生命週期執行過程

  1. A啓動B:A.onPause()→B.onCreate()→B.onStart()→B.onResume()→A.onStop
  2. B返回A:B.onPause()→A.onRestart()/A.onCreate()→A.onStart()→A.onResume()→B.onStop()

Activity執行finish後的生命週期

  1. 在onCreate中執行:onCreate -> onDestroy
  2. 在onStart中執行:onCreate -> onStart -> onStop -> onDestroy
  3. 在onResume中執行:onCreate -> onStart -> onResume -> onpause -> onStop -> onDestroy

若是用了一些解耦的策略,怎麼管理生命週期的?

  1. 能夠用Google的LifeCycle框架 0. 引入LifeCycle框架
    1. 將控件實現LifecycleObserver接口
    2. 在Activity中中註冊控件:getLifeCycle().addObderver(View);
    3. 在控件中使用: @OnLifecycleEvent(Lifecycle.Event.ON_START)

Activity的啓動流程

Android中Activity的啓動模式

  1. standard:每一次啓動,都會生成一個新的實例,放入棧頂中
  2. singleTop:經過singelTop啓動Activity時,若是發現有須要啓動的實例正在棧頂,責直接重用,不然生成新的實例
  3. singleTask:經過singleTask啓動Activity時,若是發現有須要啓動的實例正在棧中,責直接移除它上邊的實例,並重用該實例,不然生成新的實例
  4. singleInstance:經過singleTask啓動Activity時,會啓用一個新的棧結構,並將新生成的實例放入棧中。

TaskAffinity 屬性

  1. 任務相關性,標識一個Activity所需的任務棧的名字。默認狀況下,全部的Activity所需的任務棧的名字是應用的包名,固然也能夠單獨指定TaskAffinity屬性。
  2. TaskAffinity屬性主要和singleTask啓動模式和allowTaskRepeating屬性配對使用,在其餘狀況下使用沒有意義
  3. 當TaskAffinity和singleTask啓動模式配對使用的時候,它是具備該模式的Activity的目前任務棧的名字,待啓動的Activity會運行在名字和TaskAffinity相同的任務棧中
  4. 當TaskAffinity和allowTaskReparenting結合的時候,當一個應用A啓動了應用B的某個Activity C後,若是Activity C的allowTaskReparenting屬性設置爲true的話,那麼當應用B被啓動後,系統會發現Activity C所需的任務棧存在了,就將Activity C從A的任務棧中轉移到B的任務棧中。

Activity啓動模式的TaskAffinity和allowTaskReparenting

  1. TaskAffinity配合singleTask使用,指定任務棧:若是沒有TaskAffinity指定的任務棧,則開啓新棧
  2. allowTaskReparenting配合standard和singleTop使用,標明該Activity的任務棧能夠從新設置

當前應用有兩個Activity A和B,B的 android:launchMode 設置了singleTask模式,A是默認的standard,那麼A startActivity啓動B,B會新啓一個Task嗎?若是不會,那麼startActivity的Intent加上FLAG_ACTIVITY_NEW_TASK這個參數會不會呢?

設置了singleTask啓動模式的Activity,它在啓動的時會先在系統中查看屬性值affinity等於它的屬性值taskAffinity ( taskAffinity默認爲包名 ) 的任務棧是否存在。若是存在這樣的任務棧,它就會在這個任務棧中啓動,不然就會在新任務棧中啓動。android

當Intent對象包含FLAG_ACTIVITY_NEW_TASK標記時,系統在查找時仍然按Activity的taskAffinity屬性進行匹配,若是找到一個任務棧的taskAffinity與之相同,就將目標Activity壓入此任務棧中,若是找不到則建立一個新的任務棧。git

設置了singleTask啓動模式的Activity在已有的任務棧中已經存在相應的Activity實例,再啓動它時會把這個Activity實例上面的Activity所有結束掉。也就是說singleTask自帶clear top的效果。github

IntentFilter的匹配規則

IntentFilter中的過濾信息有action、category、data,爲了匹配過濾列表,須要同時匹配過濾列表中的action、category、data信息,不然匹配失敗。面試

驗證是否有當前Activity

  1. PackageManager的resolveActivity方法或者Intent的resolveActivity方法:若是找不到就會返回null
  2. PackageManager的queryIntentActivities方法:它返回全部成功匹配的Activity信息

如何獲取當前屏幕Activity的對象?

經過在Application中註冊Activity生命週期的監聽函數Application.registerActivityLifecycleCallbacks()shell

onNewIntent調用時機

一個Activity已經啓動,當再次啓動它時,若是他的啓動模式(如SingleTask,SingleTop)標明不須要從新啓動,會調用onNewIntent數據庫

除了用Intent 去啓動一個Activity,還有其餘方法嗎

使用adb shell am 命令 :如adb shell am start com.example.fuchenxuan/.MainActivity 或者 adb shell am broadcast -a magcomm.action.TOUCH_LETTER緩存

Android中子線程更新UI的方式

  1. activity.runOnUiThread(runnable)
  2. 經過主線程中的Handler進行更新
  3. 經過View的post()或者postDelayed方法進行更新

Activity之間的通訊方式

  1. Intent
  2. BroadCast或者LocalBroadCast
  3. 數據存儲的方式
  4. 靜態變量

Service


Service的啓動方式

  1. start
  2. bind

Service生命週期

Service 和Activity 的通訊方式

  1. 如上Activity和Activity的通訊方式
  2. bind方式啓動時能夠經過ServiceConnection通訊:在SerVice的onBind方法中返回一個binder,該binder能夠是AIDL方法產生的,也能夠是Messenger方法產生的

Service和Thread的區別

  1. 這是沒用任何關係的兩個概念,servie是系統的組件,Thread是CPU運行的最小單元
  2. Service不可見,咱們能夠把Service當成是不可見的Activity,用於在後臺執行一些服務;
  3. Service能夠運行在任意線程上,若是咱們生成它時沒有作特殊說明,那麼它運行在主線程上
  4. 不少時候咱們須要在Activity中開啓一個Service,再在Service中開啓一個線程,這麼作的緣由是Service只會初始化一次,咱們能夠隨時找到Service中生成的thread,使用場景舉例:
    1. 如咱們須要在多個Activity中對同一個thread進行控制時;
    2. 若是你的 Thread 須要不停地隔一段時間就要鏈接服務器作某種同步的話,該 Thread 須要在 Activity 沒有start的時候也在運行。這個時候當你 start 一個 Activity 就沒有辦法在該 Activity 裏面控制以前建立的 Thread。所以你便須要建立並啓動一個 Service ,在 Service 裏面建立、運行並控制該 Thread,這樣便解決了該問題

爲何有時須要在Service中建立子線程而不是Activity中

這是由於Activity很難對Thread進行控制,當Activity被銷燬以後,就沒有任何其它的辦法能夠再從新獲取到以前建立的子線程的實例。並且在一個Activity中建立的子線程,另外一個Activity沒法對其進行操做。可是Service就不一樣了,全部的Activity均可以與Service進行關聯,而後能夠很方便地操做其中的方法,即便Activity被銷燬了,以後只要從新與Service創建關聯,就又可以獲取到原有的Service中Binder的實例。所以,使用Service來處理後臺任務,Activity就能夠放心地finish,徹底不須要擔憂沒法對後臺任務進行控制的狀況。

IntentService

  1. IntentService 是繼承自 Service,內部經過HandlerThread啓動一個新線程處理耗時操做麼,能夠看作是Service和HandlerThread的結合體,在完成了使命以後會自動中止,適合須要在工做線程處理UI無關任務的場景
  2. 若是啓動 IntentService 屢次,那麼每個耗時操做會以工做隊列的方式在 IntentService 的 onHandleIntent 回調方法中執行,依次去執行,使用串行的方式,執行完自動結束。

IntentService生命週期是怎樣的

  1. 在全部任務執行完畢後,自動結束生命

BroadCast


BroadCast的註冊方式與區別

  1. 在manifest中靜態註冊:廣播是常駐的,App關閉後仍能接收廣播,喚醒App
  2. 動態的註冊和註銷:動態註冊的廣播生命週期和他的宿主相同,或者調用註銷方法註銷廣播

Android中發送BroadCast的方式

  1. 無序廣播:經過mContext.sendBroadcast(Intent)或mContext.sendBroadcast(Intent, String)發送的是無序廣播(後者加了權限);
  2. 經過mContext.sendOrderedBroadcast(Intent, String, BroadCastReceiver, Handler, int, String, Bundle)發送的是有序廣播(再也不推薦使用)。
  3. 在無序廣播中,全部的Receiver會接收到相同廣播;而在有序廣播中,咱們能夠爲Receiver設置優先級,優先級高的先接收廣播,並有權對廣播進行處理和決定要不要繼續向下傳送

BroadCastReceiver處理耗時操做

  1. BroadcastReceiver的生命週期只有一個回調方法onReceive(Context context, Intent intent);沒法進行耗時操做,即便啓動線程處理,也是出於非活動狀態,有可能被系統殺掉。
  2. 若是須要進行耗時操做,能夠啓動一個service處理。

廣播發送和接收的原理了解嗎

  1. 繼承BroadcastReceiver,重寫onReceive()方法。
  2. 經過Binder機制向ActivityManagerService註冊廣播。
  3. 經過Binder機制向ActivityMangerService發送廣播。
  4. ActivityManagerService查找符合相應條件的廣播(IntentFilter/Permission)的BroadcastReceiver,將廣播發送到BroadcastReceiver所在的消息隊列中。
  5. BroadcastReceiver所在消息隊列拿到此廣播後,回調它的onReceive()方法。

廣播傳輸的數據是否有限制,是多少,爲何要限制?

  1. 廣播是經過Intent攜帶須要傳遞的數據的
  2. Intent是經過Binder機制實現的
  3. Binder對數據大小有限制,不一樣room不同,通常爲1M

Localbroadcast

本地廣播,只有本進程中的receivers能接收到此廣播

實現原理(監聽者模式):

  1. LocalBroadcastManager是一個單例
  2. 在LocalBroadcastManager實例中維護一個Action和ReceiverRecord的Map.(ReceiverRecord是reveiver和intentfilter的組合)
  3. 當調用LocalBroadcastManager的sendBroadcast方法時,會從2中的map找到合適的receiver,讓後加到待執行的隊列mPendingBroadcasts,並經過Handler發送一個空消息(此Handler運行在主線程中,是建立manager時建立的)
  4. handler 的handle方法收到消息,從mPendingBroadcasts取出receiver並調用onreceive方法
    其餘:刪除方法是經過一個輔助的hashmap實現的,hashmap存儲了receiver和receiverRecord

ContentProvider


請介紹下ContentProvider是如何實現數據共享的

  1. 準確的說,ContentProvider是一個APP間共享數據的接口。一個程序能夠經過實現一個Content provider的抽象接口將本身的數據徹底暴露出去,數據能夠是SqLite中的,也能夠是文件或者其餘類型。
  2. 使用方式:
    1. 在A APP中實現建ContentProvider,並在Manifest中生命它的Uri和權限
    2. 在B APP中註冊權限,並經過ContentResolver和Uri進行增刪改查
  3. 擴展:ContentProvider底層是經過Binder機制來實現跨進程間通訊,經過匿名共享內存方式進行數據的傳輸 一個應用進程有16個Binder線程去和遠程服務進行交互,而每一個線程可佔用的緩存空間是128KB,超過會報異常。

每一個ContentProvider的操做是在哪一個線程中運行的呢(其實咱們關心的是UI線程和工做線程)?好比咱們在UI線程調用getContentResolver().query查詢數據,而當數據量很大時(或者須要進行較長時間的計算)會不會阻塞UI線程呢?

  1. ContentProvider和調用者在同一個進程,ContentProvider的方法(query/insert/update/delete等)和調用者在同一線程中
  2. ContentProvider和調用者在不一樣的進程,ContentProvider的方法會運行在它自身所在進程的一個Binder線程中

ContentProvider、ContentResolver與ContentObserver之間的關係是什麼?

  1. ContentProvider:管理數據,提供數據的增刪改查操做,數據源能夠是數據庫、文件、XML、網絡等,ContentProvider爲這些數據的訪問提供了統一的接口,能夠用來作進程間數據共享。
  2. ContentResolver:ContentResolver能夠不一樣URI操做不一樣的ContentProvider中的數據,外部進程能夠經過ContentResolver與ContentProvider進行交互。
  3. ContentObserver:觀察ContentProvider中的數據變化,並將變化通知給外界。

Fragment


Fragment生命週期

onAttach -> onCreate -> onCreateView -> onActivityCreate -> onStart -> onResume -> onPause -> onStop -> onDestoryView -> onDestory -> onDetach

遇到過哪些關於Fragment的問題,如何處理的

舉例:getActivity()空指針:這種狀況通常發生在在異步任務裏調用getActivity(),而Fragment已經onDetach()。

Fragment 有什麼優勢, Fragment和View能夠相互替換嘛

  1. Fragment爲了解決Andriod碎片化而產生的
  2. Fragment和View都有助於界面複用
  3. Fragment的複用粒度更大,包含生命週期和業務邏輯,一般包含好幾個View
  4. View一般更關注視圖的實現

Fragment add replace 區別

  1. replace 先刪除容器中的內容,再添加
  2. add直接添加,能夠配合hide適用

參考資料

LearningNotes

40 個 Android 面試題

https://www.nowcoder.com/discuss/3043

http://weixin.niurenqushi.com/article/2017-03-17/4790406.html

https://blog.csdn.net/vfush/article/details/51481127

https://blog.csdn.net/vfush/article/details/51790079

相關文章
相關標籤/搜索