生活随笔
收集整理的這篇文章主要介紹了
Android4.0 Launcher 源码分析系列(二)
小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
上一節(jié)我們研究了Launcher的整體結(jié)構(gòu),這一節(jié)我們看看整個(gè)Laucher的入口點(diǎn),同時(shí)Laucher在加載了它的布局文件Laucher.xml時(shí)都干了些什么。
我們?cè)谠创a中可以找到LauncherApplication, 它繼承了Application類,當(dāng)整個(gè)Launcher啟動(dòng)時(shí),它就是整個(gè)程序的入口。我們先來(lái)看它們?cè)贏ndroidManifest.xml中是怎么配置的。
<application android:name = "com.android.launcher2.LauncherApplication" android:label = "@string/application_name" android:icon = "@drawable/ic_launcher_home" android:hardwareAccelerated = "@bool/config_hardwareAccelerated" android:largeHeap = "@bool/config_largeHeap" > 首先通過(guò)android:name指定了整個(gè)Launcher的Application也就是入口是在com.android.launcher2.LauncherApplication這個(gè)路徑下,android:lable指定了桌面的名字是叫Launcher,如果要改名字就改values文件夾的string.xml中的相應(yīng)屬性就可以了。 android:icon指定了Laucher的圖標(biāo),這個(gè)圖標(biāo)可以在應(yīng)用程序管理器中看見,如下圖所示,是個(gè)可愛機(jī)器人住在一個(gè)小房子里面,如果需要更改Laucher的圖片,重新設(shè)置這個(gè)屬性就可以了。
?
android:hardwareAccelerated="@bool/config_hardwareAccelerated" 指定了整個(gè)應(yīng)用程序是啟用硬件加速的,這樣整個(gè)應(yīng)用程序的運(yùn)行速度會(huì)更快。
android:largeHeap="@bool/config_largeHeap" 指定了應(yīng)用程序使用了大的堆內(nèi)存,能在一定程度上避免,對(duì)內(nèi)存out of memory錯(cuò)誤的出現(xiàn)。我們可以在values文件夾的config.xml中看到對(duì)是否啟用硬件加速和大內(nèi)存的配置。如下所示:
<bool name = "config_hardwareAccelerated" > true </bool> <bool name = "config_largeHeap" > false </bool> ?
在Application中onCreate()方法通過(guò): sIsScreenLarge = screenSize == Configuration . SCREENLAYOUT_SIZE_LARGE || screenSize == Configuration . SCREENLAYOUT_SIZE_XLARGE ; 和 sScreenDensity = getResources (). getDisplayMetrics (). density ; 來(lái)判斷是否是大屏幕,同時(shí)得到它的屏幕密度。同時(shí)通過(guò)mIconCache = new IconCache(this); 來(lái)設(shè)置了應(yīng)用程序的圖標(biāo)的cache,然后申明了LauncherModel,mModel = new LauncherModel(this, mIconCache); LauncherModel主要用于加載桌面的圖標(biāo)、插件和文件夾,同時(shí)LaucherModel是一個(gè)廣播接收器,在程序包發(fā)生改變、區(qū)域、或者配置文件發(fā)生改變時(shí),都會(huì)發(fā)送廣播給LaucherModel,LaucherModel會(huì)根據(jù)不同的廣播來(lái)做相應(yīng)加載操作,此部分會(huì)在后面做詳細(xì)介紹。
在LauncherApplication完成初始化工作之后,我們就來(lái)到了Launcher.java的onCreate()方法,同樣是啟動(dòng)桌面時(shí)的一系列初始化工作。
首先需要注意的是在加載launcher布局文件時(shí)的一個(gè)TraceView的調(diào)試方法,它能夠?qū)υ谒麄冎g的方法進(jìn)行圖形化的性能分析,并且能夠具體到method 代碼如下:
if ( PROFILE_STARTUP ) { android . os . Debug . startMethodTracing ( Environment . getDataDirectory () + "/data/com.android.launcher/launcher" ); } if ( PROFILE_STARTUP ) { android . os . Debug . stopMethodTracing (); } 我指定的生成性能分析的路徑是:/data/data/com.android.launcher/launcher,啟動(dòng)launcher后我們會(huì)發(fā)現(xiàn)在指定的目錄下生成了launcher.trace文件,如下圖所示:
?
把launcher.trace文件通過(guò)DDMS pull到電腦上 , 在SDK的tools目錄里,執(zhí)行traceview工具來(lái)打開launcher.trace .如下圖所示:
?
可以看到setContentView使用了448.623ms,占整個(gè)跟蹤代碼時(shí)間的62%,所以說(shuō)在加載布局文件時(shí),肯定經(jīng)過(guò)了一系列的加載運(yùn)算,我們接著分析。
當(dāng)加載launcher布局文件的過(guò)程時(shí),最為關(guān)鍵的時(shí)對(duì)整個(gè)workspace的加載,workspace是一個(gè)自定義組件,它的繼承關(guān)系如下所示,可以看到Workspace實(shí)際上也是一個(gè)ViewGroup,可以加入其他控件。
當(dāng)ViewGroup組件進(jìn)行加載的時(shí)候首先會(huì)讀取本控件對(duì)應(yīng)的XML文件,然后Framework層會(huì)執(zhí)行它的onMeasure()方法,根據(jù)它所包含的子控件大小來(lái)計(jì)算出整個(gè)控件要在屏幕上占的大小。Workspace重寫了ViewGroup的onMeasure方法(在PagedView中),在workspace中是對(duì)5個(gè)子CellLayout進(jìn)行測(cè)量,的方法如下, 具體含義請(qǐng)看注釋: ?
@Override ?protected ?void ?onMeasure(int ?widthMeasureSpec,?int ?heightMeasureSpec)?{ ?????if ?(!mIsDataReady)?{ ? ????????super .onMeasure(widthMeasureSpec,?heightMeasureSpec); ? ????????return ; ? ????} ? ????? ????final ?int ?widthMode?=?MeasureSpec.getMode(widthMeasureSpec); ? ????final ?int ?widthSize?=?MeasureSpec.getSize(widthMeasureSpec); ? ????? ????if ?(widthMode?!=?MeasureSpec.EXACTLY)?{ ? ????????throw ?new ?IllegalStateException("Workspace?can?only?be?used?in?EXACTLY?mode." ); ? ????} ? ? ????? ? ? ? ? ????? ????final ?int ?heightMode?=?MeasureSpec.getMode(heightMeasureSpec); ? ????int ?heightSize?=?MeasureSpec.getSize(heightMeasureSpec); ? ????int ?maxChildHeight?=?0 ; ? ????? ????final ?int ?verticalPadding?=?mPaddingTop?+?mPaddingBottom; ? ????final ?int ?horizontalPadding?=?mPaddingLeft?+?mPaddingRight; ? ? ? ????? ????? ????if ?(DEBUG)?Log.d(TAG,?"PagedView.onMeasure():?" ?+?widthSize?+?",?" ?+?heightSize??+?"?mPaddingTop=" +mPaddingTop?+?"?mPaddingBottom=" +mPaddingBottom); ? ????final ?int ?childCount?=?getChildCount(); ? ????? ????for ?(int ?i?=?0 ;?i?<?childCount;?i++)?{ ? ????????? ????????final ?View?child?=?getPageAt(i); ? ????????final ?LayoutParams?lp?=?(LayoutParams)?child.getLayoutParams(); ? ? ????????int ?childWidthMode; ? ????????if ?(lp.width?==?LayoutParams.WRAP_CONTENT)?{ ? ????????????childWidthMode?=?MeasureSpec.AT_MOST; ? ????????}?else ?{ ? ????????????childWidthMode?=?MeasureSpec.EXACTLY; ? ????????} ? ? ????????int ?childHeightMode; ? ????????if ?(lp.height?==?LayoutParams.WRAP_CONTENT)?{ ? ????????????childHeightMode?=?MeasureSpec.AT_MOST; ? ????????}?else ?{ ? ????????????childHeightMode?=?MeasureSpec.EXACTLY; ? ????????} ? ? ????????final ?int ?childWidthMeasureSpec?= ? ????????????MeasureSpec.makeMeasureSpec(widthSize?-?horizontalPadding,?childWidthMode); ? ????????final ?int ?childHeightMeasureSpec?= ? ????????????MeasureSpec.makeMeasureSpec(heightSize?-?verticalPadding,?childHeightMode); ? ????????? ????????child.measure(childWidthMeasureSpec,?childHeightMeasureSpec); ? ????????maxChildHeight?=?Math.max(maxChildHeight,?child.getMeasuredHeight()); ? ????????if ?(DEBUG)?Log.d(TAG,?"\tmeasure-child" ?+?i?+?":?" ?+?child.getMeasuredWidth()?+?",?" ? ????????????????+?child.getMeasuredHeight()); ? ????} ? ? ????if ?(heightMode?==?MeasureSpec.AT_MOST)?{ ? ????????heightSize?=?maxChildHeight?+?verticalPadding; ? ????} ? ????? ????setMeasuredDimension(widthSize,?heightSize); ? ? ????? ????? ????? ????invalidateCachedOffsets(); ? ????updateScrollingIndicatorPosition(); ? ? ????if ?(childCount?>?0 )?{ ? ????????mMaxScrollX?=?getChildOffset(childCount?-?1 )?-?getRelativeChildOffset(childCount?-?1 ); ? ????}?else ?{ ? ????????mMaxScrollX?=?0 ; ? ????} ? }? 測(cè)量完畢之后就可以對(duì)子控件進(jìn)行布局了,這時(shí)候Framework層會(huì)調(diào)用PagedView 中重寫的onLayout方法。
@Override ????protected ?void ?onLayout(boolean ?changed,?int ?left,?int ?top,?int ?right,?int ?bottom)?{ ? ???????if ?(!mIsDataReady)?{ ? ???????????return ; ? ???????} ? ? ???????if ?(DEBUG)?Log.d(TAG,?"PagedView.onLayout()" ); ? ???????? ???????final ?int ?verticalPadding?=?mPaddingTop?+?mPaddingBottom; ? ???????final ?int ?childCount?=?getChildCount(); ? ???????int ?childLeft?=?0 ; ? ???????if ?(childCount?>?0 )?{ ? ???????????if ?(DEBUG)?Log.d(TAG,?"getRelativeChildOffset():?" ?+?getMeasuredWidth()?+?",?" ? ???????????????????+?getChildWidth(0 )); ? ???????????childLeft?=?getRelativeChildOffset(0 ); ? ???????????? ???????????if ?(DEBUG)?Log.d(TAG,?"childLeft:" +childLeft);?? ? ? ???????????? ???????????? ???????????if ?(mPageSpacing?<?0 )?{ ? ???????????????setPageSpacing(((right?-?left)?-?getChildAt(0 ).getMeasuredWidth())?/?2 ); ? ???????????} ? ???????} ? ? ???????for ?(int ?i?=?0 ;?i?<?childCount;?i++)?{ ? ???????????final ?View?child?=?getPageAt(i); ? ???????????if ?(child.getVisibility()?!=?View.GONE)?{ ? ???????????????final ?int ?childWidth?=?getScaledMeasuredWidth(child); ? ???????????????final ?int ?childHeight?=?child.getMeasuredHeight(); ? ???????????????int ?childTop?=?mPaddingTop; ? ???????????????if ?(mCenterPagesVertically)?{ ? ???????????????????childTop?+=?((getMeasuredHeight()?-?verticalPadding)?-?childHeight)?/?2 ; ? ???????????????} ? ??????????????? ? ???????????????if ?(DEBUG)?Log.d(TAG,?"\tlayout-child" ?+?i?+?":?" ?+?childLeft?+?",?" ?+?childTop); ? ???????????????? ???????????????child.layout(childLeft,?childTop, ? ???????????????????????childLeft?+?child.getMeasuredWidth(),?childTop?+?childHeight); ? ???????????????childLeft?+=?childWidth?+?mPageSpacing; ? ???????????} ? ???????} ? ???????? ???????? ???????if ?(mFirstLayout?&&?mCurrentPage?>=?0 ?&&?mCurrentPage?<?getChildCount())?{ ? ???????????setHorizontalScrollBarEnabled(false ); ? ???????????int ?newX?=?getChildOffset(mCurrentPage)?-?getRelativeChildOffset(mCurrentPage); ? ???????????? ???????????scrollTo(newX,?0 ); ? ???????????mScroller.setFinalX(newX); ? ???????????if ?(DEBUG)?Log.d(TAG,?"newX?is?" +newX); ? ???????????setHorizontalScrollBarEnabled(true ); ? ???????????mFirstLayout?=?false ; ? ???????} ? ? ???????if ?(mFirstLayout?&&?mCurrentPage?>=?0 ?&&?mCurrentPage?<?getChildCount())?{ ? ???????????mFirstLayout?=?false ; ? ???????} ? ???} ? ?
轉(zhuǎn)載于:https://blog.51cto.com/zuiniuwang/773412
總結(jié)
以上是生活随笔 為你收集整理的Android4.0 Launcher 源码分析系列(二) 的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
如果覺得生活随笔 網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔 推薦給好友。