極力推薦文章:歡迎收藏
Android 乾貨分享 java
`
onCreate() -> onStart() -> onResume() -> onPause() -> onStop() -> onDetroy()
`linux
service
啓動方式有兩種
一種是經過startService()
方式進行啓動
另外一種是經過bindService()
方式進行啓動。
不一樣的啓動方式他們的生命週期是不同.android
經過startService()
這種方式啓動的service
生命週期是這樣:
調用startService() --> onCreate()--> onStartConmon()--> onDestroy()
。
這種方式啓動的話,須要注意一下幾個問題
第一:當咱們經過startService
被調用之後,屢次在調用startService(),onCreate()
方法也只會被調用一次,而onStartConmon()
會被屢次調用,當咱們調用stopService()
的時候,onDestroy()
就會被調用,從而銷燬服務。
第二:當咱們經過startService
啓動時候,經過intent
傳值,在onStartConmon()
方法中獲取值的時候,必定要先判斷intent
是否爲null
。ios
經過bindService()
方式進行綁定,這種方式綁定service
生命週期:bindService-->onCreate()-->onBind()-->unBind()-->onDestroy()
bindservice
這種方式進行啓動service
好處是更加便利activity
中操做service
,若是要在activity
中調用,在須要在activity
獲取ServiceConnection
對象,經過ServiceConnection
來獲取service
中內部類的類對象,而後經過這個類對象就能夠調用類中的方法,固然這個類須要繼承Binder
對象程序員
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()
方法來啓動activity
,Instrumentation
這個類主要做用就是監控程序和系統之間的交互。而在這個execStartActivity()
方法中會獲取ActivityManagerService
的代理對象,經過這個代理對象進行啓動activity
。啓動會就會調用一個checkStartActivityResult()
方法,若是說沒有在配置清單中配置有這個組件,就會在這個方法中拋出異常了。固然最後是調用的是Application.scheduleLaunchActivity()
進行啓動activity
,而這個方法中經過獲取獲得一個ActivityClientRecord
對象,而這個ActivityClientRecord
經過handler
來進行消息的發送,系統內部會將每個activity
組件使用ActivityClientRecord
對象來進行描述,而ActivityClientRecord
對象中保存有一個LoaderApk
對象,經過這個對象調用handleLaunchActivity
來啓動activity
組件,而頁面的生命週期方法也就是在這個方法中進行調用。設計模式
此處延伸:什麼狀況下用動態註冊api
Broadcast
廣播,註冊方式主要有兩種.
第一種是靜態註冊
,也可成爲常駐型廣播,這種廣播須要在Androidmanifest.xml
中進行註冊,這中方式註冊的廣播,不受頁面生命週期的影響,即便退出了頁面,也能夠收到廣播這種廣播通常用於想開機自啓動啊等等,因爲這種註冊的方式的廣播是常駐型廣播,因此會佔用CPU
的資源。數組
第二種是動態註冊
,而動態註冊的話,是在代碼中註冊的,這種註冊方式也叫很是駐型廣播,受到生命週期的影響,退出頁面後,就不會收到廣播,咱們一般運用在更新UI方面。這種註冊方式優先級較高。最後須要解綁,否會會內存泄露瀏覽器
廣播是分爲有序廣播和無序廣播。
此處延伸:Volley
裏用的哪一種請求方式
首先HttpClient
和HttpUrlConnection
這兩種方式都支持Https
協議,都是以流的形式進行上傳或者下載數據,也能夠說是以流的形式進行數據的傳輸,還有ipv6,
以及鏈接池等功能。HttpClient
這個擁有很是多的API
,因此若是想要進行擴展的話,而且不破壞它的兼容性的話,很難進行擴展,也就是這個緣由,Google
在Android6.0
的時候,直接就棄用了這個HttpClient
.
而HttpUrlConnection
相對來講就是比較輕量級了,API
比較少,容易擴展,而且可以知足Android
大部分的數據傳輸。比較經典的一個框架volley
,在Android 2.3
版本之前都是使用Android HttpClient
,在Android 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
退到了後臺。
灰色保活
灰色保活,這種保活手段是應用範圍最普遍。它是利用系統的漏洞來啓動一個前臺的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)
機制誕生。
進程的重要性,劃分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
下有兩個子類,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,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
函數。好比onClickListener
,onKeyDown
等。
此處延伸:棧(First In Last Out)
與隊列(First In First Out)
的區別
棧與隊列的區別:
1. 隊列先進先出,棧先進後出
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
的繪製流程: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)
;
⑥、繪製滾動條。
Touch
事件分發中只有兩個主角:ViewGroup
和View
。ViewGroup
包含onInterceptTouchEvent、dispatchTouchEvent、onTouchEvent
三個相關事件。View
包含dispatchTouchEvent、onTouchEvent
兩個相關事件。
其中ViewGroup又繼承於View。
2.ViewGroup
和View
組成了一個樹狀結構,根節點爲Activity
內部包含的一個ViewGroup
。
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
進行跨進程通訊時請求隊列是同步進行的,沒法併發執行。
Binder
機制簡單理解:
在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
接口的能力。
Android
中主線程是不能進行耗時操做的,子線程是不能進行更新UI
的。因此就有了handler
,它的做用就是實現線程之間的通訊。
handler
整個流程中,主要有四個對象,handler,Message,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/ART VM
是加載類的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
:
是指程序在申請內存後,沒法釋放已申請的內存空間,一次內存泄露危害能夠忽略,但內存泄露堆積後果很嚴重,不管多少內存,早晚會被佔光
1、Handler 引發的內存泄漏。
解決:將Handler
聲明爲靜態內部類,就不會持有外部類SecondActivity
的引用,其生命週期就和外部類無關,
若是Handler
裏面須要context
的話,能夠經過弱引用方式引用外部類
2、單例模式引發的內存泄漏。
解決:Context
是ApplicationContext
,因爲ApplicationContext
的生命週期是和app
一致的,不會致使內存泄漏
3、非靜態內部類建立靜態實例引發的內存泄漏。
解決:把內部類修改成靜態的就能夠避免內存泄漏了
4、非靜態匿名內部類引發的內存泄漏。
解決:將匿名內部類設置爲靜態的。
5、註冊/反註冊未成對使用引發的內存泄漏。
註冊廣播接受器、EventBus
等,記得解綁。
6、資源對象沒有關閉引發的內存泄漏。
在這些資源不使用的時候,記得調用相應的相似close()、destroy()、recycler()、release()
等方法釋放。
7、集合對象沒有及時清理引發的內存泄漏。
一般會把一些對象裝入到集合中,當不使用的時候必定要記得及時清理集合,讓相關對象再也不被引用。
1.直接在一個Fragment
中調用另一個Fragment
中的方法
2.使用接口回調
3.使用廣播
4.Fragment
直接調用Activity
中的public
方法
字體使用sp
,dp
,多使用match_parent,wrap_content,weight
圖片資源,不一樣圖片的的分辨率,放在相應的文件夾下可以使用百分比代替。
工具:Hierarchy Viewer
分析佈局
工具:TraceView
測試分析耗時
佈局優化
響應優化
內存優化
電池使用優化
網絡優化
冷啓動: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)
。
(1)過於複雜的佈局.
(2)UI線程的複雜運算
(3)頻繁的GC
致使頻繁GC有兩個緣由:
一、內存抖動, 即大量的對象被建立又在短期內立刻被釋放.
二、瞬間產生大量的對象會嚴重佔用內存區域。
工具:Batterystats & bugreport
(1)優化網絡請求
(2)定位中使用GPS, 請記得及時關閉
網絡鏈接對用戶的影響:流量,電量,用戶等待,可在Android studio
下方logcat
旁邊那個工具Network Monitor
檢測
App
與Server
之間的API設計要考慮網絡請求的頻次, 資源的狀態等. 以便App
能夠以較少的請求來完成業務需求和界面的展現.
使用Gzip
來壓縮request
和response
, 減小傳輸數據量, 從而減小流量消耗.
能夠在獲取圖片時告知服務器須要的圖片的寬高, 以便服務器給出合適的圖片, 避免浪費.
適當的緩存, 既可讓咱們的應用看起來更快, 也能避免一些沒必要要的流量消耗.
(1)對圖片自己進行操做。
儘可能不要使用setImageBitmap、setImageResource、BitmapFactory.decodeResource
來設置一張大圖,由於這些方法在完成decode
後,最終都是經過 java 層的 createBitmap 來完成的,須要消耗更多內存.
(2)圖片進行縮放的比例,SDK
中建議其值是2
的指數值,值越大會致使圖片不清晰。
(3)不用的圖片記得調用圖片的recycle()
方法
Android
與JS
經過WebView
互相調用方法,其實是:Android
去調用JS
的代碼
WebView
的loadUrl()
,使用該方法比較簡潔,方便。可是效率比較低,獲取返回值比較困難。WebView
的evaluateJavascript()
,該方法效率高,可是4.4
以上的版本才支持,4.4
如下版本不支持。因此建議二者混合使用。JS
去調用Android
的代碼
WebView
的addJavascriptInterface()
進行對象映射 ,該方法使用簡單,僅將Android
對象和JS
對象映射便可,可是存在比較大的漏洞。漏洞產生緣由是:當JS
拿到Android
這個對象後,就能夠調用這個Android
對象中全部的方法,包括系統類(java.lang.Runtime 類)
,從而進行任意代碼執行。
解決方法:
(1)Google
在Android 4.2
版本中規定對被調用的函數以 @JavascriptInterface
進行註解從而避免漏洞攻擊。
(2)在Android 4.2
版本以前採用攔截prompt()
進行漏洞修復。
WebViewClient
的shouldOverrideUrlLoading ()
方法回調攔截 url
。這種方式的優勢:
不存在方式1
的漏洞;
缺點:JS
獲取Android
方法的返回值複雜。(ios主要用的是這個方式)
(1)Android
經過 WebViewClient
的回調方法shouldOverrideUrlLoading ()
攔截 url
(2)解析該 url
的協議
(3)若是檢測到是預先約定好的協議,就調用相應方法
WebChromeClien
t 的onJsAlert()、onJsConfirm()、onJsPrompt()
方法回調攔截JS對話框alert()、confirm()、prompt()
消息這種方式的優勢:不存在方式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(); } } } 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。` 至此,本篇已結束,若有不對的地方,歡迎您的建議與指正。同時期待您的關注,感謝您的閱讀,謝謝! 