就在前兩天迎來了最難熬的一天「冬至」。到了冬天,就有點犯困,果真是冬困秋乏春無力。因此趁着年末總結一份比較全面的面試寶典,給本身洗洗腦。溫故而知新( 如下是整理的面試寶典的核心筆記圖)
(順手留下GitHub連接,須要獲取相關面試或者面試寶典核心筆記PDF等內容的能夠本身去找)
https://github.com/xiangjiana/Android-MS
(VX:mm14525201314)java
onCreate()
-> onStart()
-> onResume()
-> onPause()
-> onStop()
-> onDetroy()
linux
service 啓動方式有兩種,一種是經過 startService()
方式進行啓動,另外一種是經過 bindService()
方式進行啓動。不一樣的啓動方式他們的生命週期是不同.android
經過 startService()
這種方式啓動的 service,生命週期是這樣:調用 startService()
-->onCreate()
--> onStartConmon()
--> onDestroy()
。ios
這種方式啓動的話,須要注意一下幾個問題:
第一: 當咱們經過 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 對象git
app 啓動的過程有兩種狀況,第一種是從桌面 launcher 上點擊相應的應用圖標,第二種是在activity 中經過調用 startActivity
來啓動一個新的 activity。github
咱們建立一個新的項目,默認的根 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 組件,而頁面的生命週期方法也就是在這個方法中進行調用。算法
此處延伸: 什麼狀況下用動態註冊
Broadcast 廣播,註冊方式主要有兩種.第一種是靜態註冊,也可成爲常駐型廣播,這種廣播須要在 Androidmanifest.xml
中進行註冊,這中方式註冊的廣播,不受頁面生命週期的影響,即便退出了頁面,也能夠收到廣播這種廣播通常用於想開機自啓動啊等等,因爲這種註冊的方式的廣播是常駐型廣播,因此會佔用CPU 的資源。設計模式
第二種是動態註冊,而動態註冊的話,是在代碼中註冊的,這種註冊方式也叫很是駐型廣播,收到生命週期的影響,退出頁面後,就不會收到廣播,咱們一般運用在更新 UI 方面。這種註冊方式優先級較高。最後須要解綁,否會會內存泄露api
廣播是分爲有序廣播和無序廣播。
此處延伸: 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
。
一、java 虛擬機基於棧。 基於棧的機器必須使用指令來載入和操做棧上數據,所需指令更多更多。
二、java 虛擬機運行的是 java 字節碼。(java 類會被編譯成一個或多個字節碼.class 文件)
一、dalvik 虛擬機是基於寄存器的
二、Dalvik 運行的是自定義的.dex 字節碼格式。(java 類被編譯成.class 文件後,會經過一個
dx 工具將全部的.class 文件轉換成一個.dex 文件,而後 dalvik 虛擬機會從其中讀取指令和數據
三、常量池已被修改成只使用 32 位的索引,以 簡化解釋器。
四、一個應用,一個虛擬機實例,一個進程(全部 android 應用的線程都是對應一個 linux 線程,都運行在本身的沙盒中,不一樣的應用在不一樣的進程中運行。每一個 android dalvik 應用程序都被賦予了一個獨立的 linux PID(app_*))
此處延伸: 進程的優先級是什麼
當前業界的 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)機制誕生。
前臺進程 (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 同樣躲避不了被殺的命運,爲了儘可能避免被殺,仍是老老實實去作好優化工做吧。因此,進程保活的根本方案終究仍是回到了性能優化上,進程永生不死終究是個徹頭徹尾的僞命題!
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)
這個問題真的很很差回答。因此這裏先來個算是比較恰當的比喻來形容下它們的關係吧。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
等。
此處延伸: 棧(First In Last Out)與隊列(First In First Out)的區別
- 隊列先進先出,棧先進後出
- 對插入和刪除操做的"限定"。 棧是限定只能在表的一端進行插入和刪除操做的線性表。隊列是限定只能在表的一端進行插入和在另外一端進行刪除操做的線性表。
- 遍歷數據速度不一樣
這是默認模式,每次激活 Activity 時都會建立 Activity 實例,並放入任務棧中。
使用場景: 大多數 Activity。
如 果 在 任 務 的 棧 頂 正 好 存 在 該 Activity 的 實 例 , 就 重 用 該 實 例 ( 會 調 用 實 例 的onNewIntent()
),不然就會建立新的實例並放入棧頂,即便棧中已經存在該 Activity 的實例,只要不在棧頂,都會建立新的實例。使用場景如新聞類或者閱讀類 App 的內容頁面。
若是在棧中已經有該 Activity 的實例,就重用該實例(會調用實例的 onNewIntent()
)。重用時,會讓該實例回到棧頂,所以在它上面的實例將會被移出棧。若是棧中不存在該實例,將會建立新的實例放入棧中。使用場景如瀏覽器的主界面。無論從多少個應用啓動瀏覽器,只會啓動主界面一次,其他狀況都會走 onNewIntent
,而且會清空主界面上面的其餘頁面。
在一個新棧中建立該 Activity 的實例,並讓多個應用共享該棧中的該 Activity 實例。一旦該模式的 Activity 實例已經存在於某個棧中,任何應用再激活該 Activity 時都會重用該棧中的實例( 會調用實例的 onNewIntent()
)。其效果至關於多個應用共享一個應用,無論誰激活該Activity 都會進入同一個應用中。使用場景如鬧鈴提醒,將鬧鈴提醒與鬧鈴設置分離。singleInstance
不要用於中間頁面,若是用於中間頁面,跳轉會有問題,好比:A -> B(singleInstance
) -> C,徹底退出後,在此啓動,首先打開的是 B
一、組合控件。這種自定義控件不須要咱們本身繪製,而是使用原生控件組合成的新控件。如標題欄。
二、繼承原有的控件。這種自定義控件在原生控件提供的方法外,能夠本身添加一些方法。如製做圓角,圓形圖片。
三、徹底自定義控件:這個 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);
⑥、繪製滾動條。
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 事件。
onSaveInstanceState(Bundle)
會在 activity 轉入後臺狀態以前被調用,也就是 onStop()
方法以前,onPause
方法以後被調用;
幀動畫:指經過指定每一幀的圖片和播放時間,有序的進行播放而造成動畫效果,好比想聽的律動條。
補間動畫: 指經過指定 View 的初始狀態、變化時間、方式,經過一系列的算法去進行圖形變換,從而造成動畫效果,主要有 Alpha、Scale、Translate、Rotate 四種效果。
注意: 只是在視圖層實現了動畫效果,並無真正改變 View 的屬性,好比滑動列表,改變標題欄的透明度。
屬性動畫: 在 Android3.0 的時候才支持,經過不斷的改變 View 的屬性,不斷的重繪而造成動畫效果。相比於視圖動畫,View 的屬性是真正改變了。好比 view 的旋轉,放大,縮小。
Android 跨進程通訊,像 intent,contentProvider,廣播,service 均可以跨進程通訊。
intent:這種跨進程方式並非訪問內存的形式,它須要傳遞一個 uri,好比說打電話。
contentProvider:這種形式,是使用數據共享的形式進行數據共享。
service:遠程服務,aidl,廣播
此處延伸: 簡述 Binder
AIDL: 每個進程都有本身的 Dalvik VM 實例,都有本身的一塊獨立的內存,都在本身的內存上存儲本身的數據,執行着本身的操做,都在本身的那片狹小的空間裏過完本身的一輩子。而 aidl 就相似與兩個進程之間的橋樑,使得兩個進程之間能夠進行數據的傳輸,跨進程通訊有多種選擇,好比BroadcastReceiver
, Messenger 等,可是 BroadcastReceiver
佔用的系統資源比較多,若是是頻繁的跨進程通訊的話顯然是不可取的;Messenger 進行跨進程通訊時請求隊列是同步進行的,沒法併發執行。
在 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驅動程序間接實現的。而BinderManager 是一個守護進程,用來管理 Service,並向 Client 提供查詢 Service 接口的能力。
Android 中主線程是不能進行耗時操做的,子線程是不能進行更新 UI的。因此就有了 handler,它的做用就是實現線程之間的通訊。
handler 整個流程中,主要有四個對象,handlerMessage
,MessageQueue
,Looper
。當應用建立的時候,就會在主線程中建立 handler 對象,
咱們經過要傳送的消息保存到 Message 中,handler 經過調用 sendMessage
方法將 Message發送到 MessageQueue
中,Looper
對象就會不斷的調用 loop()方法
不斷的從 MessageQueue
中取出 Message 交給 handler 進行處理。從而實現線程之間的通訊。
在 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 接口的能力。
咱們知道 Java 虛擬機 —— JVM 是加載類的 class 文件的,而 Android 虛擬機——Dalvik/ARTVM 是加載類的 dex 文件,
而他們加載類的時候都須要ClassLoader
,ClassLoader
有一個子類 BaseDexClassLoader
,而BaseDexClassLoader
下有一個數組——DexPathList
,是用來存放 dex 文件,當 BaseDexClassLoader
經過調用 findClass 方法時,實際上就是遍歷數組,找到相應的 dex 文件,找到,則直接將它 return。
而熱修復的解決方法就是將新的 dex 添加到該集合中,而且是在舊的 dex 的前面,因此就會優先被取出來而且 return 返回。
(1)內存溢出(OOM)和內存泄露(對象沒法被回收)的區別。
(2)引發內存泄露的緣由
( 3 ) 內存泄露檢測工具 ------>LeakCanary
內存溢出 out of memory: 是指程序在申請內存時,沒有足夠的內存空間供其使用,出現 out of memory;好比申請了一個 integer,但給它存了 long 才能存下的數,那就是內存溢出。內存溢出通俗的講就是內存不夠用。
內存泄露 memory leak: 是指程序在申請內存後,沒法釋放已申請的內存空間,一次內存泄露危害能夠忽略,但內存泄露堆積後果很嚴重,不管多少內存,早晚會被佔光
①Handler 引發的內存泄漏。
解決:將 Handler 聲明爲靜態內部類,就不會持有外部類 SecondActivity 的引用,其生命週期就和外部類無關,若是 Handler 裏面須要 context 的話,能夠經過弱引用方式引用外部類
②單例模式引發的內存泄漏。
解決:Context 是 ApplicationContext,因爲 ApplicationContext 的生命週期是和 app 一致的,不會致使內存泄漏
③非靜態內部類建立靜態實例引發的內存泄漏。
解決: 把內部類修改成靜態的就能夠避免內存泄漏了
④非靜態匿名內部類引發的內存泄漏。
解決:將匿名內部類設置爲靜態的。
⑤註冊/反註冊未成對使用引發的內存泄漏。
註冊廣播接受器、EventBus 等,記得解綁。
⑥資源對象沒有關閉引發的內存泄漏。
在這些資源不使用的時候,記得調用相應的相似 close()、destroy()、recycler()、release()等方法釋放。
⑦集合對象沒有及時清理引發的內存泄漏。
一般會把一些對象裝入到集合中,當不使用的時候必定要記得及時清理集合,讓相關對象再也不被引用。
1.直接在一個 Fragment 中調用另一個 Fragment 中的方法
2.使用接口回調
3.使用廣播
4.Fragment 直接調用 Activity 中的 public 方法
字體使用 sp,使用 dp,多使用 match_parent,wrap_content,weight
圖片資源,不一樣圖片的的分辨率,放在相應的文件夾下可以使用百分比代替。
app 優化: (工具:Hierarchy Viewer 分析佈局 工具:TraceView 測試分析耗時的)
App 啓動優化.佈局優化響應優化.內存優化.電池使用優化.網絡優化.App 啓動優化(針對冷啓動)
冷啓動: App 沒有啓動過或 App 進程被 killed, 系統中不存在該 App 進程, 此時啓動 App 即爲冷啓動。
熱啓動: 熱啓動意味着你的 App 進程只是處於後臺, 系統只是將其從後臺帶到前臺, 展現給用戶。
介於冷啓動和熱啓動之間, 通常來講在如下兩種狀況下發生:
(1)用戶 back 退出了 App, 而後又啓動. App 進程可能還在運行, 可是 activity 須要重建。
(2)用戶退出 App 後, 系統可能因爲內存緣由將 App 殺死, 進程和 activity 都須要重啓, 可是能夠在 onCreate 中將被動殺死鎖保存的狀態(saved instance state)恢復。
Application 的 onCreate(特別是第三方 SDK 初始化),首屏 Activity 的渲染都不要進行耗時操做,若是有,就能夠放到子線程或者 IntentService 中
儘可能不要過於複雜的嵌套。可使用<include>,<merge>,<ViewStub>
Android 系統每隔 16ms 會發出 VSYNC 信號重繪咱們的界面(Activity)。
①過於複雜的佈局.
②UI 線程的複雜運算
③頻繁的 GC,致使頻繁 GC 有兩個緣由:
- 內存抖動, 即大量的對象被建立又在短期內立刻被釋放.
- 瞬間產生大量的對象會嚴重佔用內存區域。
內存優化: 參考內存泄露和內存溢出部分
電池使用優化(使用工具: Batterystats & bugreport)
(1)優化網絡請求
(2)定位中使用 GPS, 請記得及時關閉
網絡優化(網絡鏈接對用戶的影響:流量,電量,用戶等待)可在Android studio下方logcat旁邊那個工具 Network Monitor 檢測
API 設計: App 與 Server 之間的 API 設計要考慮網絡請求的頻次, 資源的狀態等. 以便 App能夠以較少的請求來完成業務需求和界面的展現.
Gzip 壓縮: 使用 Gzip 來壓縮 request 和 response, 減小傳輸數據量, 從而減小流量消耗.
圖片的 Size:能夠在獲取圖片時告知服務器須要的圖片的寬高, 以便服務器給出合適的圖片,避免浪費.
網絡緩存: 適當的緩存, 既可讓咱們的應用看起來更快, 也能避免一些沒必要要的流量消耗.
(1) 對 圖 片 本 身 進 行 操 做 。 盡 量 不 要 使 用 setImageBitmap 、 setImageResource 、BitmapFactory.decodeResource 來設置一張大圖,由於這些方法在完成 decode 後,最終都是經過 java 層的 createBitmap 來完成的,須要消耗更多內存.
(2)圖片進行縮放的比例,SDK 中建議其值是 2 的指數值,值越大會致使圖片不清晰。
(3)不用的圖片記得調用圖片的 recycle()方法
Android 與 JS 經過 WebView 互相調用方法,其實是:
漏洞產生緣由是: 當 JS 拿到 Android 這個對象後,就能夠調用這個 Android 對象中全部的方法,包括系統類(java.lang.Runtime 類),從而進行任意代碼執行。
(1)Google 在 Android 4.2 版本中規定對被調用的函數以@JavascriptInterface 進行註解從而避免漏洞攻擊。
(2)在 Android 4.2 版本以前採用攔截 prompt()進行漏洞修復。
不存在方式 1 的漏洞;缺點: JS 獲取 Android 方法的返回值複雜。(ios 主要用的是這個方式)
(1)Android 經過 WebViewClient 的回調方法 shouldOverrideUrlLoading ()攔截 url
(2)解析該 url 的協議
(3)若是檢測到是預先約定好的協議,就調用相應方法
這種方式的優勢: 不存在方式 1 的漏洞;缺點:JS 獲取 Android 方法的返回值複雜。
垃圾收集算法的核心思想是:對虛擬機可用內存空間,即堆空間中的對象進行識別,若是對象正在被引用,那麼稱其爲存活對象,反之,若是對象再也不被引用,則爲垃圾對象,能夠回收其佔據的空間,用於再分配。垃圾收集算法的選擇和垃圾收集系統參數的合理調節直接影響着系統性能。
ANR 全名 Application Not Responding, 也就是"應用無響應". 當操做在一段時間內系統沒法處理時, 系統層面會彈出上圖那樣的 ANR 對話框.
(1)5s 內沒法響應用戶輸入事件(例如鍵盤輸入, 觸摸屏幕等).
(2)BroadcastReceiver 在 10s 內沒法結束
(3)Service 20s 內沒法結束(低機率)
(1)不要在主線程中作耗時的操做,而應放在子線程中來實現。如onCreate()
和onResume()
裏儘量少的去作建立操做。
(2)應用程序應該避免在 BroadcastReceiver 裏作耗時的操做或計算。
(3)避免在 Intent Receiver 裏啓動一個 Activity,由於它會建立一個新的畫面,並從當前用戶正在運行的程序上搶奪焦點。
(4)service 是運行在主線程的,因此在 service 中作耗時操做,必需要放在子線程中。
此處延伸: Double Check 的寫法被要求寫出來。
單例模式: 分爲惡漢式和懶漢式
惡漢式:
public class Singleton { private static Singleton instance = new Singleton(); public static Singleton getInstance() { return instance ; } }
懶漢式:
public class Singleton02 { private static Singleton02 instance; public static Singleton02 getInstance() { if (instance == null) { synchronized (Singleton02.class) { if (instance == null) { instance = new Singleton02(); } }
此處延伸: 手寫 mvp 例子,與 mvc 之間的區別,mvp 的優點
MVP 模式,對應着 Model--業務邏輯和實體模型,view--對應着 activity,負責 View 的繪製以及與用戶交互,Presenter--負責 View 和 Model 之間的交互,MVP 模式是在 MVC 模式的基礎上,將 Model 與 View 完全分離使得項目的耦合性更低,在 Mvc 中項目中的 activity 對應着 mvc中的 C--Controllor,而項目中的邏輯處理都是在這個 C 中處理,同時 View 與 Model 之間的交互,也是也就是說,mvc 中全部的邏輯交互和用戶交互,都是放在Controllor
中,也就是 activity中。View 和 model 是能夠直接通訊的。而 MVP 模式則是分離的更加完全,分工更加明確Model--業務邏輯和實體模型,view--負責與用戶交互,Presenter 負責完成 View 於 Model間的交互,MVP 和 MVC 最大的區別是 MVC 中是容許 Model 和 View 進行交互的,而 MVP中很明顯,Model 與 View 之間的交互由 Presenter 完成。還有一點就是 Presenter 與 View 之間的交互是經過接口的
(1)安裝和下載 Cygwin,下載 Android NDK
(2)在 ndk 項目中 JNI 接口的設計
(3)使用 C/C++實現本地方法
(4)JNI 生成動態連接庫.so 文件
(5)將動態連接庫複製到 java 工程,在 java 工程中調用,運行 java 工程便可
RecyclerView
能夠完成 ListView
,GridView
的效果,還能夠完成瀑布流的效果。同時還能夠設置列表的滾動方向(垂直或者水平);RecyclerView
中 view 的複用不須要開發者本身寫代碼,系統已經幫封裝完成了。
RecyclerView
能夠進行局部刷新。RecyclerView
提供了 API 來實現 item 的動畫效果。
若是須要頻繁的刷新數據,須要添加動畫,則 RecyclerView 有較大的優點。
若是隻是做爲列表展現,則二者區別並非很大。
Fresco 是 Facebook 推出的開源圖片緩存工具,主要特色包括:兩個內存緩存加上 Native緩存構成了三級緩存,
- 圖片存儲在安卓系統的匿名共享內存, 而不是虛擬機的堆內存中, 圖片的中間緩衝數據也存放在本地堆內存, 因此, 應用程序有更多的內存使用, 不會由於圖片加載而致使 oom,同時也減小垃圾回收器頻繁調用回收 Bitmap 致使的界面卡頓, 性能更高。
- 漸進式加載 JPEG 圖片, 支持圖片從模糊到清晰加載。
- 圖片能夠以任意的中心點顯示在 ImageView, 而不只僅是圖片的中心。
- JPEG 圖片改變大小也是在 native 進行的, 不是在虛擬機的堆內存, 一樣減小 OOM。
- 很好的支持 GIF 圖片的顯示。
- 框架較大, 影響 Apk 體積
- 使用較繁瑣
Universal-ImageLoader
:(估計因爲 HttpClient 被 Google 放棄,做者就放棄維護這個框架)
1.支持下載進度監聽
2.能夠在 View 滾動中暫停圖片加載,經過 PauseOnScrollListener 接口能夠在 View 滾動中暫停圖片加載。
3.默認實現多種內存緩存算法 這幾個圖片緩存均可以配置緩存算法,不過 ImageLoader 默認實現了較多緩存算法,如 Size 最大先刪除、使用最少先刪除、最近最少使用、先進先刪除、時間最長先刪除等。
4.支持本地緩存文件名規則定義
- 自帶統計監控功能。支持圖片緩存使用的監控,包括緩存命中率、已使用內存大小、節省的流量等。
2.支持優先級處理。每次任務調度前會選擇優先級高的任務,好比 App 頁面中 Banner 的優先級高於 Icon 時就很適用。
3.支持延遲到圖片尺寸計算完成加載
4.支持飛行模式、併發線程數根據網絡類型而變。 手機切換到飛行模式或網絡類型變換時會自動調整線程池最大併發數,好比 wifi 最大併發爲 4,4g 爲 3,3g 爲 2。 這裏 Picasso根據網絡類型來決定最大併發數,而不是 CPU 核數。
5.「無」本地緩存。無」本地緩存,不是說沒有本地緩存,而是 Picasso 本身沒有實現,交給了 Square 的另一個網絡庫 okhttp 去實現,這樣的好處是能夠經過請求 ResponseHeader 中的 Cache-Control 及 Expired 控制圖片的過時時間。
1. 不只僅能夠進行圖片緩存還能夠緩存媒體文件。 Glide 不只是一個圖片緩存,它支持 Gif、WebP、縮略圖。甚至是 Video,因此更該當作一個媒體緩存。
2. 支持優先級處理。
3. 與 Activity/Fragment 生命週期一致,支持trimMemory
。 Glide 對每一個 context 都保持一個RequestManager
,經過FragmentTransaction
保持與 Activity/Fragment 生命週期一致,而且有對應的trimMemory
接口實現可供調用。
4. 支持 okhttp、Volley。 Glide 默認經過UrlConnection
獲取數據,能夠配合 okhttp 或是Volley 使用。實際ImageLoader
、Picasso 也都支持 okhttp、Volley。
5. 內存友好。 Glide 的內存緩存有個 active 的設計,從內存緩存中取數據時,不像通常的實 現 用 get , 而 是 用 remove , 再 將 這 個 緩 存 數 據 放 到 一 個 value 爲 軟 引 用 的activeResources map 中,並計數引用數,在圖片加載完成後進行判斷,若是引用計數爲空則回收掉。內存緩存更小圖片,Glide 以 url、view_width、view_height、屏幕的分辨率等作爲聯合 key,將處理後的圖片緩存在內存緩存中,而不是原始圖片以節省大小與
Activity/Fragment 生命週期一致,支持 trimMemory。圖片默認使用默認 RGB_565 而不是ARGB_888,雖然清晰度差些,但圖片更小,也可配置到 ARGB_888。
6.Glide 能夠經過 signature 或不使用本地緩存支持 url 過時
Xutils 這個框架很是全面,能夠進行網絡請求,能夠進行圖片加載處理,能夠數據儲存,還能夠對 view 進行註解,使用這個框架很是方便,可是缺點也是很是明顯的,使用這個項目,會致使項目對這個框架依賴很是的嚴重,一旦這個框架出現問題,那麼對項目來講影響很是大的。、
OKhttp: Android 開 發中 是 能夠 直接 使 用現 成 的 api 進 行網 絡 請求 的。 就 是使 用HttpClient
,HttpUrlConnection
進行操做。okhttp 針對 Java 和 Android 程序,封裝的一個高性能的 http 請求庫,支持同步,異步,並且 okhttp 又封裝了線程池,封裝了數據轉換,封裝了參數的使用,錯誤處理等。API 使用起來更加的方便。可是咱們在項目中使用的時候仍然須要本身在作一層封裝,這樣才能使用的更加的順手。
Volley: Volley 是 Google 官方出的一套小而巧的異步請求庫,該框架封裝的擴展性很強,支持 HttpClient
、HttpUrlConnection
,甚至支持 OkHttp,並且 Volley 裏面也封裝了 ImageLoader
,因此若是你願意你甚至不須要使用圖片加載框架,不過這塊功能沒有一些專門的圖片加載框架強大,對於簡單的需求可使用,稍複雜點的需求仍是須要用到專門的圖片加載框架。
Volley 也有缺陷,好比不支持 post 大數據,因此不適合上傳文件。不過Volley 設計的初衷自己也就是爲頻繁的、數據量小的網絡請求而生。
Retrofit: Retrofit 是 Square 公司出品的默認基於 OkHttp 封裝的一套RESTful 網絡請求框架,RESTful 是目前流行的一套 api 設計的風格, 並非標準。Retrofit 的封裝能夠說是很強大,裏面涉及到一堆的設計模式,能夠經過註解直接配置請求,可使用不一樣的 http 客戶端,雖然默認是用 http ,可使用不一樣 Json Converter 來序列化數據,同時提供對 RxJava 的支持,使用 Retrofit + OkHttp + RxJava + Dagger2 能夠說是目前比較潮的一套框架,可是須要有比較高的門檻。
Volley 的優點在於封裝的更好,而使用 OkHttp 你須要有足夠的能力再進行一次封裝。而OkHttp 的優點在於性能更高,由於 OkHttp 基於 NIO 和 Okio ,因此性能上要比 Volley 更快。IO 和 NIO 這兩個都是 Java 中的概念,若是我從硬盤讀取數據,第一種方式就是程序一直等,數據讀完後才能繼續操做這種是最簡單的也叫阻塞式IO,還有一種是你讀你的,程序接着往下執行,等數據處理完你再來通知我,而後再處理回調。而第二種就是 NIO 的方式,非阻塞式, 因此 NIO 固然要比 IO 的性能要好了,而 Okio 是 Square 公司基於 IO 和 NIO 基礎上作的一個更簡單、高效處理數據流的一個庫。理論上若是 Volley 和 OkHttp 對比的話,更傾向於使用 Volley,由於 Volley 內部一樣支持使用 OkHttp,這點 OkHttp 的性能優點就沒了, 並且 Volley 自己封裝的也更易用,擴展性更好些
毫無疑問,Retrofit 默認是基於 OkHttp 而作的封裝,這點來講沒有可比性,確定首選Retrofit
這兩個庫都作了不錯的封裝,但 Retrofit 解耦的更完全,尤爲 Retrofit2.0 出來,Jake 對以前 1.0設計不合理的地方作了大量重構, 職責更細分,並且 Retrofit 默認使用 OkHttp,性能上也要比 Volley 佔優點,再有若是你的項目若是採用了 RxJava ,那更該使用 Retrofit 。因此這兩個庫相比,Retrofit 更有優點,在能掌握兩個框架的前提下該優先使用 Retrofit。可是 Retrofit門檻要比 Volley 稍高些,要理解他的原理,各類用法,想完全搞明白仍是須要花些功夫的,若是你對它只知其一;不知其二,那仍是建議在商業項目使用 Volley 吧。
(順手留下GitHub連接,須要獲取相關面試等內容的能夠本身去找)
https://github.com/xiangjiana/Android-MS