Android中高級面試33題

極力推薦文章:歡迎收藏
Android 乾貨分享 java

和您一塊兒終身學習,這裏是程序員Android

一、Activity生命週期?

`
onCreate() -> onStart() -> onResume() -> onPause() -> onStop() -> onDetroy()
`linux

二、Service生命週期?

service 啓動方式有兩種
一種是經過startService()方式進行啓動
另外一種是經過bindService()方式進行啓動。
不一樣的啓動方式他們的生命週期是不同.android

經過startService()這種方式啓動的service
生命週期是這樣:
調用startService() --> onCreate()--> onStartConmon()--> onDestroy()
這種方式啓動的話,須要注意一下幾個問題
第一:當咱們經過startService被調用之後,屢次在調用startService(),onCreate()方法也只會被調用一次,而onStartConmon()會被屢次調用,當咱們調用stopService()的時候,onDestroy()就會被調用,從而銷燬服務。
第二:當咱們經過startService啓動時候,經過intent傳值,在onStartConmon()方法中獲取值的時候,必定要先判斷intent是否爲nullios

經過bindService()方式進行綁定,這種方式綁定service
生命週期:
bindService-->onCreate()-->onBind()-->unBind()-->onDestroy() 
bindservice 這種方式進行啓動service好處是更加便利activity中操做service,若是要在activity中調用,在須要在activity獲取ServiceConnection對象,經過ServiceConnection來獲取service中內部類的類對象,而後經過這個類對象就能夠調用類中的方法,固然這個類須要繼承Binder對象程序員

三、Activity的啓動過程(不要回答生命週期)

app啓動的過程有兩種狀況
第一種是從桌面launcher上點擊相應的應用圖標
第二種是在activity中經過調用startActivity來啓動一個新的activity算法

咱們建立一個新的項目,默認的根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()方法來啓動activityInstrumentation這個類主要做用就是監控程序和系統之間的交互。而在這個execStartActivity()方法中會獲取ActivityManagerService的代理對象,經過這個代理對象進行啓動activity。啓動會就會調用一個checkStartActivityResult()方法,若是說沒有在配置清單中配置有這個組件,就會在這個方法中拋出異常了。固然最後是調用的是Application.scheduleLaunchActivity()進行啓動activity,而這個方法中經過獲取獲得一個ActivityClientRecord對象,而這個ActivityClientRecord經過handler來進行消息的發送,系統內部會將每個activity組件使用ActivityClientRecord對象來進行描述,而ActivityClientRecord對象中保存有一個LoaderApk對象,經過這個對象調用handleLaunchActivity來啓動activity組件,而頁面的生命週期方法也就是在這個方法中進行調用。設計模式

四、Broadcast註冊方式與區別 

此處延伸:什麼狀況下用動態註冊api

Broadcast廣播,註冊方式主要有兩種.
第一種是靜態註冊,也可成爲常駐型廣播,這種廣播須要在Androidmanifest.xml中進行註冊,這中方式註冊的廣播,不受頁面生命週期的影響,即便退出了頁面,也能夠收到廣播這種廣播通常用於想開機自啓動啊等等,因爲這種註冊的方式的廣播是常駐型廣播,因此會佔用CPU的資源。數組

 

第二種是動態註冊,而動態註冊的話,是在代碼中註冊的,這種註冊方式也叫很是駐型廣播,受到生命週期的影響,退出頁面後,就不會收到廣播,咱們一般運用在更新UI方面。這種註冊方式優先級較高。最後須要解綁,否會會內存泄露瀏覽器

廣播是分爲有序廣播和無序廣播。

 

五、HttpClient與HttpUrlConnection的區別 

此處延伸:Volley裏用的哪一種請求方式

首先HttpClientHttpUrlConnection 這兩種方式都支持Https協議,都是以流的形式進行上傳或者下載數據,也能夠說是以流的形式進行數據的傳輸,還有ipv6,以及鏈接池等功能。HttpClient這個擁有很是多的API,因此若是想要進行擴展的話,而且不破壞它的兼容性的話,很難進行擴展,也就是這個緣由,GoogleAndroid6.0的時候,直接就棄用了這個HttpClient.

HttpUrlConnection相對來講就是比較輕量級了,API比較少,容易擴展,而且可以知足Android大部分的數據傳輸。比較經典的一個框架volley,在Android 2.3版本之前都是使用Android HttpClient,在Android 2.3之後就使用了HttpUrlConnection

 

六、java虛擬機和Dalvik虛擬機的區別 

Java虛擬機:

一、java虛擬機基於棧。 
基於棧的機器必須使用指令來載入和操做棧上數據,所需指令更多更多。
二、java虛擬機運行的是java字節碼。
java類會被編譯成一個或多個字節碼.class文件.

Dalvik虛擬機:

一、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退到了後臺。

灰色保活
灰色保活,這種保活手段是應用範圍最普遍。它是利用系統的漏洞來啓動一個前臺的Service進程,與普通的啓動方式區別在於,它不會在系統通知欄處出現一個Notification,看起來就如同運行着一個後臺Service進程同樣。這樣作帶來的好處就是,用戶沒法察覺到你運行着一個前臺進程(由於看不到Notification),但你的進程優先級又是高於普通後臺進程的。那麼如何利用系統的漏洞呢,大體的實現思路和代碼以下:
思路一:API < 18,啓動前臺Service時直接傳入new Notification()
思路二:API >= 18,同時啓動兩個id相同的前臺Service,而後再將後啓動的Servicestop處理
熟悉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同樣躲避不了被殺的命運,爲了儘可能避免被殺,仍是老老實實去作好優化工做吧。

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

 

 

八、講解一下Context 

Context是一個抽象基類。在翻譯爲上下文,也能夠理解爲環境,是提供一些程序的運行環境基礎信息。Context下有兩個子類,ContextWrapper是上下文功能的封裝類,而ContextImpl則是上下文功能的實現類。而ContextWrapper又有三個直接的子類, ContextThemeWrapperServiceApplication。其中,ContextThemeWrapper是一個帶主題的封裝類,而它有一個直接子類就是Activity,因此ActivityService以及ApplicationContext是不同的,只有Activity須要主題,Service不須要主題。
Context一共有三種類型,分別是Application、ActivityService。這三個類雖然分別各類承擔着不一樣的做用,但它們都屬於Context的一種,而它們具體Context的功能則是由ContextImpl類去實現的,所以在絕大多數場景下,Activity、ServiceApplication這三種類型的Context都是能夠通用的。
不過有幾種場景比較特殊,好比啓動Activity,還有彈出Dialog。出於安全緣由的考慮,Android是不容許ActivityDialog憑空出現的,一個Activity的啓動必需要創建在另外一個Activity的基礎之上,也就是以此造成的返回棧。而Dialog則必須在一個Activity上面彈出(除非是System Alert類型的Dialog),所以在這種場景下,咱們只能使用Activity類型的Context,不然將會出錯。

 

getApplicationContext()getApplication()方法獲得的對象都是同一個application對象,只是對象的類型不同。

Context數量 = Activity數量 + Service數量 + 1 (1爲Application)

 

九、理解Activity,View,Window三者關係

這個問題真的很很差回答。因此這裏先來個算是比較恰當的比喻來形容下它們的關係吧。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函數。好比onClickListeneronKeyDown等。

 

十、四種LaunchMode及其使用場景

此處延伸:棧(First In Last Out)與隊列(First In First Out)的區別

棧與隊列的區別:

1. 隊列先進先出,棧先進後出

  1. 對插入和刪除操做的"限定"。 棧是限定只能在表的一端進行插入和刪除操做的線性表。 隊列是限定只能在表的一端進行插入和在另外一端進行刪除操做的線性表。
  2. 遍歷數據速度不一樣

standard 模式
這是默認模式,每次激活Activity時都會建立Activity實例,並放入任務棧中。使用場景:大多數Activity

singleTop 模式
若是在任務的棧頂正好存在該Activity的實例,就重用該實例( 會調用實例的 onNewIntent() ),不然就會建立新的實例並放入棧頂,即便棧中已經存在該Activity的實例,只要不在棧頂,都會建立新的實例。使用場景如新聞類或者閱讀類App的內容頁面。

singleTask 模式
若是在棧中已經有該Activity的實例,就重用該實例(會調用實例的 onNewIntent() )。重用時,會讓該實例回到棧頂,所以在它上面的實例將會被移出棧。若是棧中不存在該實例,將會建立新的實例放入棧中。使用場景如瀏覽器的主界面。無論從多少個應用啓動瀏覽器,只會啓動主界面一次,其他狀況都會走onNewIntent,而且會清空主界面上面的其餘頁面。

singleInstance 模式
在一個新棧中建立該Activity的實例,並讓多個應用共享該棧中的該Activity實例。一旦該模式的Activity實例已經存在於某個棧中,任何應用再激活該Activity時都會重用該棧中的實例( 會調用實例的 onNewIntent() )。其效果至關於多個應用共享一個應用,無論誰激活該 Activity 都會進入同一個應用中。使用場景如鬧鈴提醒,將鬧鈴提醒與鬧鈴設置分離。singleInstance不要用於中間頁面,若是用於中間頁面,跳轉會有問題,好比:A -> B (singleInstance) -> C,徹底退出後,在此啓動,首先打開的是B。

 

十一、View的繪製流程

自定義控件:

一、組合控件。這種自定義控件不須要咱們本身繪製,而是使用原生控件組合成的新控件。如標題欄。
二、繼承原有的控件。這種自定義控件在原生控件提供的方法外,能夠本身添加一些方法。如製做圓角,圓形圖片。
三、徹底自定義控件:這個View上所展示的內容所有都是咱們本身繪製出來的。好比說製做水波紋進度條。

 

View的繪製流程:OnMeasure()——>OnLayout()——>OnDraw()

 

第一步:OnMeasure():測量視圖大小。從頂層父View到子View遞歸調用measure方法,measure方法又回調OnMeasure
第二步:OnLayout():肯定View位置,進行頁面佈局。從頂層父View向子View的遞歸調用view.layout方法的過程,即父View根據上一步measureView所獲得的佈局大小和佈局參數,將子View放在合適的位置上。
第三步:OnDraw():繪製視圖。
ViewRoot建立一個Canvas對象,而後調用OnDraw()

六個步驟:
①、繪製視圖的背景;
②、保存畫布的圖層(Layer)
③、繪製View的內容;
④、繪製View子視圖,若是沒有就不用;
⑤、還原圖層(Layer)
⑥、繪製滾動條。

 

十二、View,ViewGroup事件分發

  1. Touch事件分發中只有兩個主角:ViewGroupView

ViewGroup
包含onInterceptTouchEvent、dispatchTouchEvent、onTouchEvent三個相關事件。
View
包含dispatchTouchEvent、onTouchEvent兩個相關事件。
其中ViewGroup又繼承於View。

2.ViewGroupView組成了一個樹狀結構,根節點爲Activity內部包含的一個ViewGroup

3.觸摸事件由Action_Down、Action_Move、Aciton_UP組成,其中一次完整的觸摸事件中,DownUp都只有一個,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函數,即父類ViewdispatchTouchEvent方法。在全部子View都不處理的狀況下,觸發AcitivityonTouchEvent方法。

7.onInterceptTouchEvent有兩個做用:
1.攔截Down事件的分發。
2.停止Up和Move事件向目標View傳遞,使得目標View所在的ViewGroup捕獲UpMove事件。

 

1三、保存Activity狀態

onSaveInstanceState(Bundle)會在activity轉入後臺狀態以前被調用,也就是onStop()方法以前,onPause方法以後被調用;

 

1四、Android中的幾種動畫

幀動畫:
指經過指定每一幀的圖片和播放時間,有序的進行播放而造成動畫效果,好比想聽的律動條。

補間動畫:
指經過指定View的初始狀態、變化時間、方式,經過一系列的算法去進行圖形變換,從而造成動畫效果,主要有Alpha、Scale、Translate、Rotate四種效果。
注意:只是在視圖層實現了動畫效果,並無真正改變View的屬性,好比滑動列表,改變標題欄的透明度。

屬性動畫:
Android3.0的時候才支持,經過不斷的改變View的屬性,不斷的重繪而造成動畫效果。相比於視圖動畫,View的屬性是真正改變了。好比view的旋轉,放大,縮小。

 

1五、Android中跨進程通信的幾種方式

Android 跨進程通訊,像intent,contentProvider,廣播,service均可以跨進程通訊。

intent:
這種跨進程方式並非訪問內存的形式,它須要傳遞一個uri,好比說打電話。

contentProvider:
這種形式,是使用數據共享的形式進行數據共享。

service:
遠程服務,好比aidl

廣播:
廣播 包含靜態廣播,動態廣播。
 

1六、AIDL理解

此處延伸:簡述Binder

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提供輔助管理的功能,而ClientService正是在Binder驅動程序和Service Manager提供的基礎設施上實現C/S 之間的通訊。其中Binder驅動程序提供設備文件/dev/binder與用戶控件進行交互,

Client、Service,Service Manager經過openioctl文件操做相應的方法與Binder驅動程序進行通訊。而ClientService之間的進程間通訊是經過Binder驅動程序間接實現的。而Binder Manager是一個守護進程,用來管理Service,並向Client提供查詢Service接口的能力。

 

1七、Handler的原理

Android中主線程是不能進行耗時操做的,子線程是不能進行更新UI的。因此就有了handler,它的做用就是實現線程之間的通訊。

handler整個流程中,主要有四個對象,
handler,Message,MessageQueue,Looper。當應用建立的時候,就會在主線程中建立handler對象,

咱們經過要傳送的消息保存到Message中,handler經過調用sendMessage方法將Message發送到MessageQueue中,Looper對象就會不斷的調用loop()方法

不斷的從MessageQueue中取出Message交給handler進行處理。從而實現線程之間的通訊。

 

 

1八、Binder機制原理

Android系統的Binder機制中,是有Client,Service,ServiceManager,Binder驅動程序組成的,其中Client,service,Service Manager運行在用戶空間,Binder驅動程序是運行在內核空間的。而Binder就是把這4種組件粘合在一塊的粘合劑,其中核心的組件就是Binder驅動程序,Service Manager提供輔助管理的功能,而ClientService正是在Binder驅動程序和Service Manager提供的基礎設施上實現C/S 之間的通訊。其中Binder驅動程序提供設備文件/dev/binder與用戶控件進行交互,Client、Service,Service Manager經過openioctl文件操做相應的方法與Binder驅動程序進行通訊。而ClientService之間的進程間通訊是經過Binder驅動程序間接實現的。而Binder Manager是一個守護進程,用來管理Service,並向Client提供查詢Service接口的能力。

 

1九、熱修復的原理

咱們知道Java虛擬機 —— JVM 是加載類的class文件的,而Android虛擬機——Dalvik/ART VM 是加載類的dex文件,而他們加載類的時候都須要ClassLoader,ClassLoader有一個子BaseDexClassLoader,而BaseDexClassLoader下有一個數組——DexPathList,是用來存放dex文件,當BaseDexClassLoader經過調用findClass方法時,實際上就是遍歷數組,找到相應的dex文件,找到,則直接將它return。而熱修復的解決方法就是將新的dex添加到該集合中,而且是在舊的dex的前面,因此就會優先被取出來而且return返回。

 

20、Android內存泄露及管理

(1)內存溢出(OOM)和內存泄露(對象沒法被回收)的區別。 
(2)引發內存泄露的緣由
(3) 內存泄露檢測工具 ------>LeakCanary

 

內存溢出 out of memory
是指程序在申請內存時,沒有足夠的內存空間供其使用,出現out of memory
好比申請了一個integer,但給它存了long才能存下的數,那就是內存溢出。內存溢出通俗的講就是內存不夠用。

內存泄露 memory leak
是指程序在申請內存後,沒法釋放已申請的內存空間,一次內存泄露危害能夠忽略,但內存泄露堆積後果很嚴重,不管多少內存,早晚會被佔光

內存泄露緣由:

1、Handler 引發的內存泄漏。
解決:將Handler聲明爲靜態內部類,就不會持有外部類SecondActivity的引用,其生命週期就和外部類無關,
若是Handler裏面須要context的話,能夠經過弱引用方式引用外部類

2、單例模式引發的內存泄漏。
解決:ContextApplicationContext,因爲ApplicationContext的生命週期是和app一致的,不會致使內存泄漏

3、非靜態內部類建立靜態實例引發的內存泄漏。
解決:把內部類修改成靜態的就能夠避免內存泄漏了

4、非靜態匿名內部類引發的內存泄漏。
解決:將匿名內部類設置爲靜態的。

5、註冊/反註冊未成對使用引發的內存泄漏。
註冊廣播接受器、EventBus等,記得解綁。

6、資源對象沒有關閉引發的內存泄漏。
在這些資源不使用的時候,記得調用相應的相似close()、destroy()、recycler()、release()等方法釋放。

7、集合對象沒有及時清理引發的內存泄漏。
一般會把一些對象裝入到集合中,當不使用的時候必定要記得及時清理集合,讓相關對象再也不被引用。

 

2一、Fragment與Fragment、Activity通訊的方式

1.直接在一個Fragment中調用另一個Fragment中的方法
2.使用接口回調
3.使用廣播
4.Fragment直接調用Activity中的public方法

 

2二、Android UI適配

字體使用sp,
dp,多使用match_parent,wrap_content,weight
圖片資源,不一樣圖片的的分辨率,放在相應的文件夾下可以使用百分比代替。

2三、app優化

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)恢復。

啓動優化:

ApplicationonCreate(特別是第三方SDK初始化),首屏Activity的渲染都不要進行耗時操做,若是有,就能夠放到子線程或者IntentService中。

佈局優化

儘可能不要過於複雜的嵌套。可使用<include>,<merge>,<ViewStub>

響應優化

Android系統每隔16ms會發出VSYNC信號重繪咱們的界面(Activity)

頁面卡頓的緣由:

(1)過於複雜的佈局.
(2)UI線程的複雜運算
(3)頻繁的GC
致使頻繁GC有兩個緣由:
一、內存抖動, 即大量的對象被建立又在短期內立刻被釋放.
二、瞬間產生大量的對象會嚴重佔用內存區域。

 

電池使用優化(

工具:Batterystats & bugreport
(1)優化網絡請求
(2)定位中使用GPS, 請記得及時關閉

 

網絡優化

網絡鏈接對用戶的影響:流量,電量,用戶等待,可在Android studio下方logcat旁邊那個工具Network Monitor檢測

API設計:

AppServer之間的API設計要考慮網絡請求的頻次, 資源的狀態等. 以便App能夠以較少的請求來完成業務需求和界面的展現.

Gzip壓縮:

使用Gzip來壓縮requestresponse, 減小傳輸數據量, 從而減小流量消耗.

圖片的Size:

能夠在獲取圖片時告知服務器須要的圖片的寬高, 以便服務器給出合適的圖片, 避免浪費.

網絡緩存:

適當的緩存, 既可讓咱們的應用看起來更快, 也能避免一些沒必要要的流量消耗.

 

2四、圖片優化

(1)對圖片自己進行操做。
儘可能不要使用setImageBitmap、setImageResource、BitmapFactory.decodeResource來設置一張大圖,由於這些方法在完成decode後,最終都是經過 java 層的 createBitmap 來完成的,須要消耗更多內存.
(2)圖片進行縮放的比例,SDK中建議其值是2的指數值,值越大會致使圖片不清晰。
(3)不用的圖片記得調用圖片的recycle()方法

 

2五、HybridApp WebView和JS交互

AndroidJS經過WebView互相調用方法,其實是:
Android去調用JS的代碼

  1. 經過WebViewloadUrl(),使用該方法比較簡潔,方便。可是效率比較低,獲取返回值比較困難。
  2. 經過WebViewevaluateJavascript(),該方法效率高,可是4.4以上的版本才支持,4.4如下版本不支持。因此建議二者混合使用。

JS去調用Android的代碼

  1. 經過WebViewaddJavascriptInterface()進行對象映射 ,該方法使用簡單,僅將Android對象和JS對象映射便可,可是存在比較大的漏洞。

漏洞產生緣由是:當JS拿到Android這個對象後,就能夠調用這個Android對象中全部的方法,包括系統類(java.lang.Runtime 類),從而進行任意代碼執行。
解決方法:
(1)GoogleAndroid 4.2 版本中規定對被調用的函數以 @JavascriptInterface進行註解從而避免漏洞攻擊。
(2)在Android 4.2版本以前採用攔截prompt()進行漏洞修復。

  1. 經過 WebViewClient shouldOverrideUrlLoading ()方法回調攔截 url

這種方式的優勢:
不存在方式1的漏洞;
缺點:JS獲取Android方法的返回值複雜。(ios主要用的是這個方式)
(1)Android經過 WebViewClient 的回調方法shouldOverrideUrlLoading ()攔截 url
(2)解析該 url 的協議
(3)若是檢測到是預先約定好的協議,就調用相應方法

  1. 經過 WebChromeClient 的onJsAlert()、onJsConfirm()、onJsPrompt()方法回調攔截JS對話框alert()、confirm()、prompt() 消息

這種方式的優勢:不存在方式1的漏洞;缺點:JS獲取Android方法的返回值複雜。

 

2六、JAVA GC原理

垃圾收集算法的核心思想是:
對虛擬機可用內存空間,即堆空間中的對象進行識別,若是對象正在被引用,那麼稱其爲存活對象,反之,若是對象再也不被引用,則爲垃圾對象,能夠回收其佔據的空間,用於再分配。垃圾收集算法的選擇和垃圾收集系統參數的合理調節直接影響着系統性能。

 

2七、ANR

ANR全名Application Not Responding, 也就是"應用無響應". 當操做在一段時間內系統沒法處理時, 系統層面會彈出上圖那樣的ANR對話框.

產生緣由:
(1)5s內沒法響應用戶輸入事件(例如鍵盤輸入, 觸摸屏幕等).
(2)BroadcastReceiver10s內沒法結束
(3)Service 20s內沒法結束(低機率)

 

解決方式:
(1)不要在主線程中作耗時的操做,而應放在子線程中來實現。如onCreate()onResume()裏儘量少的去作建立操做。
(2)應用程序應該避免在BroadcastReceiver裏作耗時的操做或計算。
(3)避免在Intent Receiver裏啓動一個Activity,由於它會建立一個新的畫面,並從當前用戶正在運行的程序上搶奪焦點。
(4)service是運行在主線程的,因此在service中作耗時操做,必需要放在子線程中。

2八、設計模式

此處延伸: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(); 
                } 
            } 
        } 
        return instance; 
    } 
}
 ```
#2九、Xutils, OKhttp, Volley, Retrofit對比

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 VS OkHttp:

`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` 自己封裝的也更易用,擴展性更好些。

OkHttp VS Retrofit

毫無疑問,`Retrofit` 默認是基於` OkHttp` 而作的封裝,這點來講沒有可比性,確定首選` Retrofit`。

Volley VS Retrofit

這兩個庫都作了不錯的封裝,但`Retrofit`解耦的更完全,尤爲`Retrofit2.0`出來,`Jake`對以前`1.0`設計不合理的地方作了大量重構, 職責更細分,並且`Retrofit`默認使用`OkHttp,`性能上也要比`Volley`佔優點,再有若是你的項目若是採用了`RxJava `,那更該使用`  Retrofit` 。因此這兩個庫相比,`Retrofit`更有優點,在能掌握兩個框架的前提下該優先使用 `Retrofit`。可是`Retrofit`門檻要比`Volley`稍高些,要理解他的原理,各類用法,想完全搞明白仍是須要花些功夫的,若是你對它只知其一;不知其二,那仍是建議在商業項目使用Volley吧。

#30、MVP,MVC,MVVM

此處延伸:手寫`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`之間的交互是經過接口的

 


#3一、JNI 

(1)安裝和下載`Cygwin`,下載 `Android NDK`
(2)在`ndk`項目中`JNI`接口的設計
(3)使用`C/C++`實現本地方法
(4)`JNI`生成動態連接庫`.so`文件
(5)將動態連接庫複製到`java`工程,在`java`工程中調用,運行`java`工程便可

 

#3二、RecyclerView和ListView的區別

`RecyclerView`能夠完成`ListView,GridView`的效果,還能夠完成瀑布流的效果。同時還能夠設置列表的滾動方向(垂直或者水平);
`RecyclerView`中`view`的複用不須要開發者本身寫代碼,系統已經幫封裝完成了。
`RecyclerView`能夠進行局部刷新。
`RecyclerView`提供了`API`來實現`item`的動畫效果。

在性能上:
若是須要頻繁的刷新數據,須要添加動畫,則`RecyclerView`有較大的優點。
若是隻是做爲列表展現,則二者區別並非很大。

 

#3三、Universal-ImageLoader,Picasso,Fresco,Glide對比

#####Fresco
是 `Facebook `推出的開源圖片緩存工具,主要特色包括:兩個內存緩存加上 `Native` 緩存構成了三級緩存,

優勢:
1. 圖片存儲在安卓系統的匿名共享內存, 而不是虛擬機的堆內存中, 圖片的中間緩衝數據也存放在本地堆內存, 因此, 應用程序有更多的內存使用, 不會由於圖片加載而致使`oom`, 同時也減小垃圾回收器頻繁調用回收` Bitmap `致使的界面卡頓, 性能更高。
2. 漸進式加載 `JPEG` 圖片, 支持圖片從模糊到清晰加載。
3. 圖片能夠以任意的中心點顯示在 `ImageView,` 而不只僅是圖片的中心。
4. `JPEG `圖片改變大小也是在` native `進行的, 不是在虛擬機的堆內存, 一樣減小 `OOM`。
5. 很好的支持` GIF `圖片的顯示。

缺點:
1. 框架較大, 影響 Apk 體積
2. 使用較繁瑣

 

#####Universal-ImageLoader:
估計因爲HttpClient被Google放棄,做者就放棄維護這個框架


優勢:
1.支持下載進度監聽
2.能夠在` View `  滾動中暫停圖片加載,經過 `PauseOnScrollListener` 接口能夠在` View` 滾動中暫停圖片加載。
3.默認實現多種內存緩存算法 這幾個圖片緩存均可以配置緩存算法,不過` ImageLoader `默認實現了較多緩存算法,如 `Size `最大先刪除、使用最少先刪除、最近最少使用、先進先刪除、時間最長先刪除等。
4.支持本地緩存文件名規則定義

     

#####Picasso 優勢
1. 自帶統計監控功能。支持圖片緩存使用的監控,包括緩存命中率、已使用內存大小、節省的流量等。
2.支持優先級處理。每次任務調度前會選擇優先級高的任務,好比 `App `頁面中` Banner `的優先級高於` Icon `時就很適用。
3.支持延遲到圖片尺寸計算完成加載
4.支持飛行模式、併發線程數根據網絡類型而變。 手機切換到飛行模式或網絡類型變換時會自動調整線程池最大併發數,好比 `wifi `最大併發爲` 4,4g 爲 3,3g 爲 2`。  這裏` Picasso `根據網絡類型來決定最大併發數,而不是` CPU `核數。
5.「無」本地緩存。無」本地緩存,不是說沒有本地緩存,而是 `Picasso `本身沒有實現,交給了` Square `的另一個網絡庫 `okhttp` 去實現,這樣的好處是能夠經過請求 `Response Header `中的 `Cache-Control` 及 `Expired` 控制圖片的過時時間。

##### Glide 優勢

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。`


至此,本篇已結束,若有不對的地方,歡迎您的建議與指正。同時期待您的關注,感謝您的閱讀,謝謝!

![微信關注公衆號:  程序員Android,領福利](https://upload-images.jianshu.io/upload_images/5851256-f3309bcfcbd098a8.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
相關文章
相關標籤/搜索