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