對於這些專題的詳解,專門作了一個983頁的PDF版本,以下php
(更多完整項目下載。未完待續。源碼。圖文知識後續上傳github。)
能夠點擊關於我聯繫我獲取
(VX:mm14525201314)css
工做原理 :在必定時間間隔內,經過不斷對值進行改變,並不斷將該值賦給對象的屬性,從而實現該對象在該屬性上的動畫效果。html
ValueAnimator
:經過不斷控制值的變化(初始值->結束值),將值手動賦值給對象的屬性,再不斷調用View的invalidate()方法,去不斷onDraw
重繪view,達到動畫的效果。主要的三種方法:java
a)ValueAnimator.ofInt(int values)
:估值器是整型估值器IntEaluatorandroid
b)ValueAnimator.ofFloat(float values)
:估值器是浮點型估值器FloatEaluatorgit
c) ValueAnimator.ofObject(ObjectEvaluator, start, end)
:將初始值以對象的形式過渡到結束值,經過操做對象實現動畫效果,須要實現Interpolator
接口,自定義估值器github
估值器TypeEvalutor
,設置動畫如何從初始值過渡到結束值的邏輯。插值器(Interpolator
)決定值的變化模式(勻速、加速等);估值器(TypeEvalutor
)決定值的具體變化數值。面試
// 自定義估值器,須要實現TypeEvaluator接口 public class ObjectEvaluator implements TypeEvaluator{ // 複寫evaluate(),在evaluate()裏寫入對象動畫過渡的邏輯 @Override public Object evaluate(float fraction, Object startValue, Object endValue) { // 參數說明 // fraction:表示動畫完成度(根據它來計算當前動畫的值) // startValue、endValue:動畫的初始值和結束值 ... // 寫入對象動畫過渡的邏輯 return value; // 返回對象動畫過渡的邏輯計算後的值 }
ObjectAnimator
:直接對對象的屬性值進行改變操做,從而實現動畫效果ObjectAnimator
繼承自ValueAnimator
類,底層的動畫實現機制仍是基本值的改變。它是不斷控制值的變化,再不斷自動賦給對象的屬性,從而實現動畫效果。這裏的自動賦值,是經過調用對象屬性的set/get方法進行自動賦值,屬性動畫初始值若是有就直接取,沒有則調用屬性的get()方法獲取,當值更新變化時,經過屬性的set()方法進行賦值。每次賦值都是調用view的postInvalidate()/invalidate()
方法不斷刷新視圖(實際調用了onDraw()
方法進行了重繪視圖)。數據庫
//Object 須要操做的對象; propertyName 須要操做的對象的屬性; values動畫初始值&結束值, //若是是兩個值,則從a->b值過渡,若是是三值,則從a->b->c ObjectAnimator animator = ObjectAnimator.ofFloat(Object object, String propertyName, float ...values);
若是採用ObjectAnimator
類實現動畫,操做的對象的屬性必須有get()和set()方法。api
其餘用法:
1)AnimatorSet組合動畫
AnimatorSet.play(Animator anim) :播放當前動畫 AnimatorSet.after(long delay) :將現有動畫延遲x毫秒後執行 AnimatorSet.with(Animator anim) :將現有動畫和傳入的動畫同時執行 AnimatorSet.after(Animator anim) :將現有動畫插入到傳入的動畫以後執行 AnimatorSet.before(Animator anim) : 將現有動畫插入到傳入的動畫以前執行
2) ViewPropertyAnimator直接對屬性操做,View.animate()返回的是一個ViewPropertyAnimator對象,以後的調用方法都是基於該對象的操做,調用每一個方法返回值都是它自身的實例
View.animate().alpha(0f).x(500).y(500).setDuration(500).setInterpolator()
3)設置動畫監聽
Animation.addListener(new AnimatorListener() { @Override public void onAnimationStart(Animation animation) { //動畫開始時執行 } @Override public void onAnimationRepeat(Animation animation) { //動畫重複時執行 } @Override public void onAnimationCancel()(Animation animation) { //動畫取消時執行 } @Override public void onAnimationEnd(Animation animation) { //動畫結束時執行 } });
主要有四種AlpahAnimation
\ ScaleAnimation
\ RotateAnimation
\ TranslateAnimation
四種,對透明度、縮放、旋轉、位移四種動畫。在調用View.startAnimation
時,先調用View.setAnimation(Animation)
方法給本身設置一個Animation對象,再調用invalidate來重繪本身。在View.draw(Canvas, ViewGroup, long)方法中進行了getAnimation()
, 並調用了drawAnimation(ViewGroup, long, Animation, boolean)
方法,此方法調用Animation.getTranformation()
方法,再調用applyTranformation()
方法,該方法中主要是對Transformation.getMatrix().setTranslate/setRotate/setAlpha/setScale
來設置相應的值,這個方法系統會以60FPS
的頻率進行調用。具體是在調Animation.start()方法中會調用animationHandler.start()
方法,從而調用了scheduleAnimation()
方法,這裏會調用mChoreographer.postCallback(Choregrapher.CALLBACK_ANIMATION, this, null)
放入事件隊列中,等待doFrame()
來消耗事件。
當一個 ChildView
要重畫時,它會調用其成員函數 invalidate() 函數將通知其 ParentView
這個 ChildView
要重畫,這個過程一直向上遍歷到 ViewRoot
,當 ViewRoot
收到這個通知後就會調用ViewRoot
中的 draw 函數從而完成繪製。View::onDraw() 有一個畫布參數 Canvas, 畫布顧名思義就是畫東西的地方,Android 會爲每個 View 設置好畫布,View 就能夠調用 Canvas 的方法,好比:drawText
, drawBitmap
, drawPath
等等去畫內容。每個 ChildView
的畫布是由其 ParentView
設置的,ParentView
根據 ChildView
在其內部的佈局來調整 Canvas,其中畫布的屬性之一就是定義和 ChildView
相關的座標系,默認是橫軸爲 X 軸,從左至右,值逐漸增大,豎軸爲 Y 軸,從上至下,值逐漸增大。
ParentView
來不斷調整
ChildView
的畫布座標系來實現的,在
ParentView
的
dispatchDraw
方法會被調用。
dispatchDraw() { .... Animation a = ChildView.getAnimation() Transformation tm = a.getTransformation(); Use tm to set ChildView's Canvas; Invalidate(); .... }
這裏有兩個類:Animation 和 Transformation,這兩個類是實現動畫的主要的類,Animation 中主要定義了動畫的一些屬性好比開始時間、持續時間、是否重複播放等,這個類主要有兩個重要的函數:getTransformation
和 applyTransformation
,在 getTransformation
中 Animation 會根據動畫的屬性來產生一系列的差值點,而後將這些差值點傳給 applyTransformation
,這個函數將根據這些點來生成不一樣的 Transformation,Transformation 中包含一個矩陣和 alpha 值,矩陣是用來作平移、旋轉和縮放動畫的,而 alpha 值是用來作 alpha 動畫的(簡單理解的話,alpha 動畫至關於不斷變換透明度或顏色來實現動畫),調用 dispatchDraw
時會調用 getTransformation
來獲得當前的 Transformation。某一個 View 的動畫的繪製並非由他本身完成的而是由它的父 view 完成。
補間動畫TranslateAnimation,View位置移動了,但是點擊區域還在原來的位置,爲何?
View在作動畫是,根據動畫時間的插值,計算出一個Matrix,不停的invalidate,在onDraw中的Canvas上使用這個計算出來的Matrix去draw view的內容。
某個view的動畫繪製並非由它本身完成,而是由它的父view完成,使它的父view畫布進行了移動,而點擊時仍是點擊原來的畫布。使得它看起來變化了。
主要記住一些大版本變化:
android3.0 代號Honeycomb, 引入Fragments, ActionBar,屬性動畫,硬件加速
android4.0 代號Ice Cream,API14:截圖功能,人臉識別,虛擬按鍵,3D優化驅動
android5.0 代號Lollipop API21:調整桌面圖標及部件透明度等
android6.0 代號M Marshmallow API23,軟件權限管理,安卓支付,指紋支持,App關聯,
android7.0 代號N Preview API24,多窗口支持(不影響Activity生命週期),增長了JIT編譯器,引入了新的應用簽名方案APK Signature Scheme v2(縮短應用安裝時間和更多未受權APK文件更改保護),嚴格了權限訪問
android8.0 代號O API26,取消靜態廣播註冊,限制後臺進程調用手機資源,桌面圖標自適應
android9.0 代號P API27,增強電池管理,系統界面添加了Home虛擬鍵,提供人工智能API,支持免打擾模式
requestLayout()
方法 :會致使調用measure()過程 和 layout()過程 。 說明:只是對View樹從新佈局layout過程包括measure()和layout()過程,若是view的l,t,r,b沒有必變,那就不會觸發onDraw
;可是若是此次刷新是在動畫裏,mDirty非空,就會致使onDraw
。
onLayout()
方法(若是該View是ViewGroup
對象,須要實現該方法,對每一個子視圖進行佈局)
onDraw()
方法繪製視圖自己 (每一個View都須要重載該方法,ViewGroup
不須要實現該方法)
drawChild()
去從新回調每一個子視圖的draw()方法
View.invalidate()
: 層層上傳到父級,直到傳遞到ViewRootImpl
後觸發了scheduleTraversals()
,而後整個View樹開始從新按照View繪製流程進行重繪任務。
invalidate
:在ui線程刷新view
postInvalidate
:在工做線程刷新view(底層仍是handler)其實它的原理就是invalidate+handler
View.postInvalidate
最終會調用ViewRootImpl.dispatchInvalidateDelayed()
方法
public void dispatchInvalidateDelayed(View view, long delayMilliseconds) { Message msg = mHandler.obtainMessage(MSG_INVALIDATE, view); mHandler.sendMessageDelayed(msg, delayMilliseconds); }
這裏的mHandler
是ViewRootHandler
實例,在該Handler的handleMessage
方法中調用了view.invalidate()方法。
case MSG_INVALIDATE: ((View) msg.obj).invalidate(); break;
Activity:是安卓四大組件之一,負責界面展現、用戶交互與業務邏輯處理;
Window:就是負責界面展現以及交互的職能部門,就至關於Activity的下屬,Activity的生命週期方法負責業務的處理;
View:就是放在Window容器的元素,Window是View的載體,View是Window的具體展現。
三者的關係: Activity經過Window來實現視圖元素的展現,window能夠理解爲一個容器,盛放着一個個的view,用來執行具體的展現工做。
1)在要在onDraw
或是onLayout()
中去建立對象,由於onDraw()
方法可能會被頻繁調用,能夠在view的構造函數中進行建立對象;
2)下降view的刷新頻率,儘量減小沒必要要的調用invalidate()方法。或是調用帶四種參數不一樣類型的invalidate(),而不是調用無參的方法。無參變量須要刷新整個view,而帶參數的方法只需刷新指定部分的view。在onDraw()方法中減小冗餘代碼。
3)使用硬件加速,GPU硬件加速能夠帶來性能增長。
4)狀態保存與恢復,若是因內存不足,Activity置於後臺被殺重啓時,View應儘量保存本身屬性,能夠重寫onSaveInstanceState
和onRestoreInstanceState
方法,狀態保存。
使用@TargetApi
註解·
當代碼中有比AndroidManifest
中設置的android:minSdkVersion
版本更高的方法,此時編譯器會提示警告,解決方法是在方法上加上
@SuppressLint("NewApi")
或者@TargetApi()
。但它們僅是屏蔽了android lint錯誤,在方法中還要判斷版本作不一樣的操做。
@SuppressLint("NewApi")
屏蔽一切新api
中才能使用的方法報的android lint錯誤
@TargetApi()
只屏蔽某一新api
中才能使用的方法報的android lint錯誤,如@TargetApi(11)
若是在方法中用了只有API14
纔開始有的方法,仍是會報錯。
1)域名解析
瀏覽器會先搜索自身DNS
緩存且對應的IP地址沒有過時;若未找到則搜索操做系統自身的DNS
緩存;若還未找到則讀本地的hotsts
文件;還未找到會在TCP/IP
設置的本地DNS
服務器上找,若是要查詢的域名在本地配置的區域資源中,則完成解析;不然根據本地DNS
服務器會請求根DNS
服務器;根DNS
服務器是13臺根DNS
,會一級一級往下找。
2)TCP三次握手
客戶端先發送SYN=1,ACK=0,序列號seq=x報文;(SYN在鏈接創建時用來同步序號,SYN=1,ACK=0表明這是一個鏈接請求報文,對方若贊成創建鏈接,則應在響應報文中使SYN=1,ACK=1)
服務器返回SYN=1,ACK=1,seq=y, ack=x+1;
客戶端再一次確認,但不用SYN了,回覆服務端, ACK=1, seq=x+1, ack=y+1
3)創建TCP鏈接後發起HTTP請求
客戶端按照指定的格式開始向服務端發送HTTP請求,HTTP請求格式由四部分組成,分別是請求行、請求頭、空行、消息體,服務端接收到請求後,解析HTTP請求,處理完成邏輯,最後返回一個具備標準格式的HTTP響應給客戶端。
4)服務器響應HTTP請求
服務器接收處理完請求後返回一個HTTP響應消息給客戶端,HTTP響應信息格式包括:狀態行、響應頭、空行、消息體
5)瀏覽器解析HTML代碼,請求HTML代碼中的資源
瀏覽器拿到html文件後,就開始解析其中的html代碼,遇到js/css/image等靜態資源時,向服務器發起一個http請求,若是返回304狀態碼,瀏覽器會直接讀取本地的緩存文件。不然開啓線程向服務器請求下載。
6)瀏覽器對頁面進行渲染並呈現給用戶
7)TCP的四次揮手
當客戶端沒有東西要發送時就要釋放鏈接(提出中斷鏈接能夠是Client也能夠是Server),客戶端會發送一個FIN=1的沒有數據的報文,進入FIN_WAIT狀態,服務端收到後會給客戶端一個確認,此時客戶端不能發送數據,但可接收信息。
二者均可以用來實現網絡請求,android4.4以後的HttpUrlConnection的實現是基於okhttp
在onMeasure()
的getDefaultSize()
的默認實現中,當view的測量模式是AT_MOST或EXACTLY時,View的大小都會被設置成子View MeasureSpec
的specSize
.子view的MeasureSpec
值是根據子View的佈局參數和父容器的MeasureSpec
值計算得來。當子view的佈局參數是wrap_content時,對應的測量模式是AT_MOST,大小是parentSize,
原理:IntentService
是繼承Service的一個抽象類,它在onCreate()
方法中建立了一個HandlerThread
,並啓動該線程。HandlerThread
是帶有本身消息隊列和Looper
的線程,根據HandlerThread
的looper
建立一個Handler,這樣IntentService
的ServiceHandler
的handleMessage()
方法就運行在子線程中。handleMessage
中調用了onHandleIntent()
方法,它是一個抽象方法,繼承IntentService
類須要實現該方法,把耗時操做放在onHandleIntent()
方法中,等耗時操做運行完成後,會調用stopSelf()
方法,服務會調用onDestory()
方法消毀本身。若是onHandleIntent()
中的耗時操做未運行完前就調用了stopSelf()
方法,服務調用onDestory()
方法,但耗時操做會繼續運行,直至運行完畢。若是同時屢次啓動IntentService
,任務會放在一個隊列中,onCreate()
和onDestory()
方法都只會運行一次。
做用:用來處理後臺耗時操做,如讀取數據庫或是本地文件等。
(更多完整項目下載。未完待續。源碼。圖文知識後續上傳github。)
領取完整版PDF