日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 运维知识 > Android >内容正文

Android

Android4.0 Launcher 源码分析系列(二)

發(fā)布時(shí)間:2025/5/22 Android 37 豆豆
生活随笔 收集整理的這篇文章主要介紹了 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中是怎么配置的。

<applicationandroid: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; ?
  • ????} ?
  • ????//得到寬度的模式(在配置文件中對(duì)應(yīng)的是match_parent?或者?wrap_content)和其大小 ?
  • ????final?int?widthMode?=?MeasureSpec.getMode(widthMeasureSpec); ?
  • ????final?int?widthSize?=?MeasureSpec.getSize(widthMeasureSpec); ?
  • ????//寬度必須是match_parent,否則會(huì)拋出異常。 ?
  • ????if?(widthMode?!=?MeasureSpec.EXACTLY)?{ ?
  • ????????throw?new?IllegalStateException("Workspace?can?only?be?used?in?EXACTLY?mode."); ?
  • ????} ?
  • ?
  • ????/*?Allow?the?height?to?be?set?as?WRAP_CONTENT.?This?allows?the?particular?case ?
  • ?????*?of?the?All?apps?view?on?XLarge?displays?to?not?take?up?more?space?then?it?needs.?Width ?
  • ?????*?is?still?not?allowed?to?be?set?as?WRAP_CONTENT?since?many?parts?of?the?code?expect ?
  • ?????*?each?page?to?have?the?same?width. ?
  • ?????*/?
  • ????//高度允許是wrap_content,因?yàn)樵诖笃聊坏那闆r下,會(huì)占了多余的位置 ?
  • ????final?int?heightMode?=?MeasureSpec.getMode(heightMeasureSpec); ?
  • ????int?heightSize?=?MeasureSpec.getSize(heightMeasureSpec); ?
  • ????int?maxChildHeight?=?0; ?
  • ????//得到在豎值方向上和水平方向上的Padding? ?
  • ????final?int?verticalPadding?=?mPaddingTop?+?mPaddingBottom; ?
  • ????final?int?horizontalPadding?=?mPaddingLeft?+?mPaddingRight; ?
  • ?
  • ?
  • ????//?The?children?are?given?the?same?width?and?height?as?the?workspace ?
  • ????//?unless?they?were?set?to?WRAP_CONTENT ?
  • ????if?(DEBUG)?Log.d(TAG,?"PagedView.onMeasure():?"?+?widthSize?+?",?"?+?heightSize??+?"?mPaddingTop="+mPaddingTop?+?"?mPaddingBottom="+mPaddingBottom); ?
  • ????final?int?childCount?=?getChildCount(); ?
  • ????//對(duì)workspace的子View進(jìn)行遍歷,從而對(duì)它的幾個(gè)子view進(jìn)行測(cè)量。 ?
  • ????for?(int?i?=?0;?i?<?childCount;?i++)?{ ?
  • ????????//?disallowing?padding?in?paged?view?(just?pass?0) ?
  • ????????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); ?
  • ????????//對(duì)子View的大小進(jìn)行設(shè)置,傳入width和height參數(shù) ?
  • ????????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; ?
  • ????} ?
  • ????//存儲(chǔ)測(cè)量后的寬度和高度 ?
  • ????setMeasuredDimension(widthSize,?heightSize); ?
  • ?
  • ????//?We?can't?call?getChildOffset/getRelativeChildOffset?until?we?set?the?measured?dimensions. ?
  • ????//?We?also?wait?until?we?set?the?measured?dimensions?before?flushing?the?cache?as?well,?to ?
  • ????//?ensure?that?the?cache?is?filled?with?good?values. ?
  • ????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()"); ?
  • ???????//豎值方向的Padding ?
  • ???????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); ?
  • ???????????//偏移量為0 ?
  • ???????????if?(DEBUG)?Log.d(TAG,?"childLeft:"+childLeft);?? ?
  • ?
  • ???????????//?Calculate?the?variable?page?spacing?if?necessary ?
  • ???????????//?如果mPageSpacing小于0的話,就重新計(jì)算mPageSpacing,并且給它賦值。 ?
  • ???????????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); ?
  • ???????????????//把5個(gè)CellLayout布局到相應(yīng)的位置,layout的4個(gè)參數(shù)分別是?左、上、右、下。 ?
  • ???????????????child.layout(childLeft,?childTop, ?
  • ???????????????????????childLeft?+?child.getMeasuredWidth(),?childTop?+?childHeight); ?
  • ???????????????childLeft?+=?childWidth?+?mPageSpacing; ?
  • ???????????} ?
  • ???????} ?
  • ???????//第一次布局完畢之后,就根據(jù)當(dāng)前頁(yè)偏移量(當(dāng)前頁(yè)距離Workspace最左邊的距離)滾動(dòng)到默認(rèn)的頁(yè)面去,第一次布局時(shí) ?
  • ???????//默認(rèn)的當(dāng)前頁(yè)是3,則它的便宜量就是兩個(gè)CellLayout的寬度。 ?
  • ???????if?(mFirstLayout?&&?mCurrentPage?>=?0?&&?mCurrentPage?<?getChildCount())?{ ?
  • ???????????setHorizontalScrollBarEnabled(false); ?
  • ???????????int?newX?=?getChildOffset(mCurrentPage)?-?getRelativeChildOffset(mCurrentPage); ?
  • ???????????//滾動(dòng)到指定的位置 ?
  • ???????????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ò),歡迎將生活随笔推薦給好友。