onCreate() -> onStart() -> onResume() -> onPause() -> onStop() -> onDetroy()html
service 啓動方式有兩種,一種是經過startService()方式進行啓動,另外一種是經過bindService()方式進行啓動。不一樣的啓動方式他們的生命週期是不同.java
經過startService()這種方式啓動的service,生命週期是這樣:調用startService() --> onCreate()--> onStartConmon()--> onDestroy()。這種方式啓動的話,須要注意一下幾個問題,第一:當咱們經過startService被調用之後,屢次在調用startService(),onCreate()方法也只會被調用一次,而onStartConmon()會被屢次調用當咱們調用stopService()的時候,onDestroy()就會被調用,從而銷燬服務。第二:當咱們經過startService啓動時候,經過intent傳值,在onStartConmon()方法中獲取值的時候,必定要先判斷intent是否爲null。linux
經過bindService()方式進行綁定,這種方式綁定service,生命週期走法:bindService-->onCreate()-->onBind()-->unBind()-->onDestroy() bingservice 這種方式進行啓動service好處是更加便利activity中操做service,好比加入service中有幾個方法,a,b ,若是要在activity中調用,在須要在activity獲取ServiceConnection對象,經過ServiceConnection來獲取service中內部類的類對象,而後經過這個類對象就能夠調用類中的方法,固然這個類須要繼承Binder對象android
app啓動的過程有兩種狀況,第一種是從桌面launcher上點擊相應的應用圖標,第二種是在activity中經過調用startActivity來啓動一個新的activity。ios
咱們建立一個新的項目,默認的根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的資源。api
第二種是動態註冊,而動態註冊的話,是在代碼中註冊的,這種註冊方式也叫很是駐型廣播,收到生命週期的影響,退出頁面後,就不會收到廣播,咱們一般運用在更新UI方面。這種註冊方式優先級較高。最後須要解綁,否會會內存泄露數組
廣播是分爲有序廣播和無序廣播。
此處延伸: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字節碼。(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退到了後臺。以下方的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)的區別
棧與隊列的區別:
2. 對插入和刪除操做的"限定"。 棧是限定只能在表的一端進行插入和刪除操做的線性表。 隊列是限定只能在表的一端進行插入和在另外一端進行刪除操做的線性表。
3. 遍歷數據速度不一樣
standard 模式
這是默認模式,每次激活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);⑥、繪製滾動條。
1. Touch事件分發中只有兩個主角: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 進行跨進程通訊時請求隊列是同步進行的,沒法併發執行。
Binde機制簡單理解:
在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:是指程序在申請內存後,沒法釋放已申請的內存空間,一次內存泄露危害能夠忽略,但內存泄露堆積後果很嚴重,不管多少內存,早晚會被佔光
解決:將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沒有啓動過或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檢測
API設計:App與Server之間的API設計要考慮網絡請求的頻次, 資源的狀態等. 以便App能夠以較少的請求來完成業務需求和界面的展現.
Gzip壓縮:使用Gzip來壓縮request和response, 減小傳輸數據量, 從而減小流量消耗.
圖片的Size:能夠在獲取圖片時告知服務器須要的圖片的寬高, 以便服務器給出合適的圖片, 避免浪費.
網絡緩存:適當的緩存, 既可讓咱們的應用看起來更快, 也能避免一些沒必要要的流量消耗.
最終都是經過java層的createBitmap來完成的,須要消耗更多內存.
(2)圖片進行縮放的比例,SDK中建議其值是2的指數值,值越大會致使圖片不清晰。
(3)不用的圖片記得調用圖片的recycle()方法
Android與JS經過WebView互相調用方法,其實是:
Android去調用JS的代碼
1. 經過WebView的loadUrl(),使用該方法比較簡潔,方便。可是效率比較低,獲取返回值比較困難。
2. 經過WebView的evaluateJavascript(),該方法效率高,可是4.4以上的版本才支持,4.4如下版本不支持。因此建議二者混合使用。
JS去調用Android的代碼
1. 經過WebView的addJavascriptInterface()進行對象映射 ,該方法使用簡單,僅將Android對象和JS對象映射便可,可是存在比較大的漏洞。
漏洞產生緣由是:當JS拿到Android這個對象後,就能夠調用這個Android對象中全部的方法,包括系統類(java.lang.Runtime 類),從而進行任意代碼執行。
解決方式:
(1)Google 在Android 4.2 版本中規定對被調用的函數以 @JavascriptInterface進行註解從而避免漏洞攻擊。
(2)在Android 4.2版本以前採用攔截prompt()進行漏洞修復。
2. 經過 WebViewClient 的shouldOverrideUrlLoading ()方法回調攔截 url 。這種方式的優勢:不存在方式1的漏洞;缺點:JS獲取Android方法的返回值複雜。(ios主要用的是這個方式)
(1)Android經過 WebViewClient 的回調方法shouldOverrideUrlLoading ()攔截 url
(2)解析該 url 的協議
(3)若是檢測到是預先約定好的協議,就調用相應方法
3. 經過 WebChromeClient 的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; } }
此處延伸:手寫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 緩存構成了三級緩存,
優勢:
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.支持本地緩存文件名規則定義
1. 自帶統計監控功能。支持圖片緩存使用的監控,包括緩存命中率、已使用內存大小、節省的流量等。
2.支持優先級處理。每次任務調度前會選擇優先級高的任務,好比 App 頁面中 Banner 的優先級高於 Icon 時就很適用。
3.支持延遲到圖片尺寸計算完成加載
4.支持飛行模式、併發線程數根據網絡類型而變。 手機切換到飛行模式或網絡類型變換時會自動調整線程池最大併發數,好比 wifi 最大併發爲 4,4g 爲 3,3g 爲 2。 這裏 Picasso 根據網絡類型來決定最大併發數,而不是 CPU 核數。
5.「無」本地緩存。無」本地緩存,不是說沒有本地緩存,而是 Picasso 本身沒有實現,交給了 Square 的另一個網絡庫 okhttp 去實現,這樣的好處是能夠經過請求 Response Header 中的 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 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吧。
(1)這兩個方法來自不一樣的類,sleep是來自Thread,wait是來自Object;
(2)sleep方法沒有釋放鎖,而wait方法釋放了鎖。
(3)wait,notify,notifyAll只能在同步控制方法或者同步控制塊裏面使用,而sleep能夠在任何地方使用。
start()方法是用來啓動新建立的線程,而start()內部調用了run()方法,這和直接調用run()方法是不同的,若是直接調用run()方法,
則和普通的方法沒有什麼區別。
一、final變量即爲常量,只能賦值一次。
二、final方法不能被子類重寫。
三、final類不能被繼承。
在加載類的過程當中完成靜態變量的內存分配,可用類名直接訪問(方便),固然也能夠經過對象來訪問(可是這是不推薦的)。
static代碼塊是類加載時,初始化自動執行的。
static方法能夠直接經過類名調用,任何的實例也均可以調用,所以static方法中不能用this和super關鍵字,
不能直接訪問所屬類的實例變量和實例方法(就是不帶static的成員變量和成員成員方法),只能訪問所屬類的靜態成員變量和成員方法。
四、String,StringBuffer,StringBuilder區別
一、三者在執行速度上:StringBuilder > StringBuffer > String (因爲String是常量,不可改變,拼接時會從新建立新的對象)。
二、StringBuffer是線程安全的,StringBuilder是線程不安全的。(因爲StringBuffer有緩衝區)
一、重載:一個類中能夠有多個相同方法名的,可是參數類型和個數都不同。這是重載。
二、重寫:子類繼承父類,則子類能夠經過實現父類中的方法,從而新的方法把父類舊的方法覆蓋。
此處延伸:https的實現原理
一、https協議須要到ca申請證書,通常免費證書較少,於是須要必定費用。
二、http是超文本傳輸協議,信息是明文傳輸,https則是具備安全性的ssl加密傳輸協議。
三、http和https使用的是徹底不一樣的鏈接方式,用的端口也不同,前者是80,後者是443。
四、http的鏈接很簡單,是無狀態的;HTTPS協議是由SSL+HTTP協議構建的可進行加密傳輸、身份認證的網絡協議,比http協議安全。
https實現原理:
(1)客戶使用https的URL訪問Web服務器,要求與Web服務器創建SSL鏈接。
(2)Web服務器收到客戶端請求後,會將網站的證書信息(證書中包含公鑰)傳送一份給客戶端。
(3)客戶端的瀏覽器與Web服務器開始協商SSL鏈接的安全等級,也就是信息加密的等級。
(4)客戶端的瀏覽器根據雙方贊成的安全等級,創建會話密鑰,而後利用網站的公鑰將會話密鑰加密,並傳送給網站。
(5)Web服務器利用本身的私鑰解密出會話密鑰。
(6)Web服務器利用會話密鑰加密與客戶端之間的通訊。
tcp/ip的五層模型:
從下到上:物理層->數據鏈路層->網絡層->傳輸層->應用層
其中tcp/ip位於模型中的網絡層,處於同一層的還有ICMP(網絡控制信息協議)。http位於模型中的應用層
因爲tcp/ip是面向鏈接的可靠協議,而http是在傳輸層基於tcp/ip協議的,因此說http是可靠的數據傳輸協議。
HTTP鏈接最顯著的特色是客戶端發送的每次請求都須要服務器回送響應,在請求結束後,會主動釋放鏈接。
從創建鏈接到關閉鏈接的過程稱爲「一次鏈接」。
tcp是面向鏈接的,因爲tcp鏈接須要三次握手,因此可以最低限度的下降風險,保證鏈接的可靠性。
udp 不是面向鏈接的,udp創建鏈接前不須要與對象創建鏈接,不管是發送仍是接收,都沒有發送確認信號。因此說udp是不可靠的。
因爲udp不須要進行確認鏈接,使得UDP的開銷更小,傳輸速率更高,因此實時行更好。
創建Socket鏈接至少須要一對套接字,其中一個運行與客戶端--ClientSocket,一個運行於服務端--ServiceSocket
一、服務器監聽:服務器端套接字並不定位具體的客戶端套接字,而是處於等待鏈接的狀態,實時監控網絡狀態,等待客戶端的鏈接請求。
二、客戶端請求:指客戶端的套接字提出鏈接請求,要鏈接的目標是服務器端的套接字。注意:客戶端的套接字必須描述他要鏈接的服務器的套接字,
指出服務器套接字的地址和端口號,而後就像服務器端套接字提出鏈接請求。
發給客戶端,一旦客戶端確認了此描述,雙方就正式創建鏈接。而服務端套接字則繼續處於監聽狀態,繼續接收其餘客戶端套接字的鏈接請求。
【問題1】爲何鏈接的時候是三次握手,關閉的時候倒是四次握手?
答:由於當Server端收到Client端的SYN鏈接請求報文後,能夠直接發送SYN+ACK報文。其中ACK報文是用來應答的,SYN報文是用來同步的。可是關閉鏈接時,當Server端收到FIN報文時,極可能並不會當即關閉SOCKET,因此只能先回復一個ACK報文,告訴Client端,"你發的FIN報文我收到了"。只有等到我Server端全部的報文都發送完了,我才能發送FIN報文,所以不能一塊兒發送。故須要四步握手。
【問題2】爲何TIME_WAIT狀態須要通過2MSL(最大報文段生存時間)才能返回到CLOSE狀態?
答:雖然按道理,四個報文都發送完畢,咱們能夠直接進入CLOSE狀態了,可是咱們必須假象網絡是不可靠的,有能夠最後一個ACK丟失。因此TIME_WAIT狀態就是用來重發可能丟失的ACK報文。在Client發送出最後的ACK回覆,但該ACK可能丟失。Server若是沒有收到ACK,將不斷重複發送FIN片斷。因此Client不能當即關閉,它必須確認Server接收到了該ACK。Client會在發送出ACK以後進入到TIME_WAIT狀態。Client會設置一個計時器,等待2MSL的時間。若是在該時間內再次收到FIN,那麼Client會重發ACK並再次等待2MSL。所謂的2MSL是兩倍的MSL(Maximum Segment Lifetime)。MSL指一個片斷在網絡中最大的存活時間,2MSL就是一個發送和一個回覆所需的最大時間。若是直到2MSL,Client都沒有再次收到FIN,那麼Client推斷ACK已經被成功接收,則結束TCP鏈接。
【問題3】爲何不能用兩次握手進行鏈接?
答:3次握手完成兩個重要的功能,既要雙方作好發送數據的準備工做(雙方都知道彼此已準備好),也要容許雙方就初始序列號進行協商,這個序列號在握手過程當中被髮送和確認。
如今把三次握手改爲僅須要兩次握手,死鎖是可能發生的。做爲例子,考慮計算機S和C之間的通訊,假定C給S發送一個鏈接請求分組,S收到了這個分組,併發 送了確認應答分組。按照兩次握手的協定,S認爲鏈接已經成功地創建了,能夠開始發送數據分組。但是,C在S的應答分組在傳輸中被丟失的狀況下,將不知道S 是否已準備好,不知道S創建什麼樣的序列號,C甚至懷疑S是否收到本身的鏈接請求分組。在這種狀況下,C認爲鏈接還未創建成功,將忽略S發來的任何數據分 組,只等待鏈接確認應答分組。而S在發出的分組超時後,重複發送一樣的分組。這樣就造成了死鎖。
【問題4】若是已經創建了鏈接,可是客戶端忽然出現故障了怎麼辦?
TCP還設有一個保活計時器,顯然,客戶端若是出現故障,服務器不能一直等下去,白白浪費資源。服務器每收到一次客戶端的請求後都會從新復位這個計時器,時間一般是設置爲2小時,若兩小時尚未收到客戶端的任何數據,服務器就會發送一個探測報文段,之後每隔75分鐘發送一次。若一連發送10個探測報文仍然沒反應,服務器就認爲客戶端出了故障,接着就關閉鏈接。
原文地址: https://www.cnblogs.com/huangjialin/p/8657696.html,轉載請註明原創
閱讀更多
在這裏得到的不只僅是技術!