launcher 分析

Launcher是Android系统的桌面系统,是比较重要也比较复杂的程序,这里对其代码做一个分析,希望起到抛砖引玉的作用。


1. Launcher有什么? live folder , widget , shortcut , wallpaper ,见 onActivityResult

2. UI 分成 3 部分: workspace,  slibingdrawer,  deletezone

3. Menu: 见 onCreateOptionsMenu in launcher.java

4. launcher 类是个 activity, 遵循 activity 的生命周期。

5. 资源文件比较多,这里只关注 Layout 相关的文件



代码分析的主线:


1.  了解类

2.  了解类的关系




Launcher工程中的类:







AddAdapter: 维护了 live fold  , widget , shortcut , wallpaper 4 个 ListItem , 长按桌面会显示该列表

AllAppsGridView :显示 APP 的网格

ApplicationInfo :一个可启动的应用

ApplicationsAdapter : gridview 的 adapter

BubbleTextView: 一个定制了的 textview

CellLayout: 屏幕网格化

DeleteZone : UI 的一部分

DragController , dragscroller, dragsource, droptarget: 支持拖拽操作

DragLayer :内部支持拖拽的 viewgroup

FastBitmapDrawable :工具

Folder : Icons 的集合

FolderIcon: 出现在 workspace 的 icon 代表了一个 folder

FolderInfo: ItemInfo 子类

HandleView :一个 imageview 。

InstallShortcutReceiver , UninstallShortcutReceiver :一个 broadcastrecier

ItemInfo: 代表 Launcher 中一个 Item (例如 folder )

Launcher: Launcher 程序的主窗口

LauncherApplication :在 VM 中设置参数

LauncherAppWidgetHost , LauncherAppWidgetHostView ,: Widget 相关

LauncherModel : MVC 中的 M

LauncherProvider :一个 contentprovider ,为 Launcher 存储信息

LauncherSettings: 设置相关的工具

LiveFolder , LiveFolderAdapter , LiveFolderIcon , LiveFolderInfo : livefolder 相关

Search : 搜索

UserFolder , UserFolderInfo :文件夹包含 applications ,shortcuts

Utilities: 小工具

WallpaperChooser :选择 wallpaper 的 activity

Workspace: 屏幕上的一块区域

widget : 代表启动的 widget 实例,例如搜索



Launcher中类的关系,见下图(由于篇幅有限,不能把所有关系一一画出)。





总结

1) Launcher中实现了MVC模式(M:launchermode , V:draglayer ,C: launcher),以此为主线,可以得到 Launcher对各个组件管理的细节(如drag的实现)。

2) 如果开始就深入各个实现细节则会发现千头万绪,很难有个清醒的方向。


Launcher分析(列出主要的流程)2010-09-29

Tag:
android2010-09-2814:59:08阅读0评论0字号:大中小订阅Launcher分析(列出主要的流程)

我们来看看settings的manifest文档

<manifestxmlns:android="http://schemas.android.com/apk/res/android"

package="com.android.settings"

android:sharedUserId="android.uid.system">

<uses-permissionandroid:name="com.google.android.providers.gmail.permission.WRITE_GMAIL"/>

<uses-permissionandroid:name="com.google.android.providers.gmail.permission.READ_GMAIL"/>

<uses-permissionandroid:name="android.permission.WRITE_SETTINGS"/>

<uses-permissionandroid:name="android.permission.WRITE_SECURE_SETTINGS"/>

<uses-permissionandroid:name="android.permission.DEVICE_POWER"/>

<uses-permissionandroid:name="android.permission.CHANGE_CONFIGURATION"/>

<uses-permissionandroid:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>

<uses-permissionandroid:name="android.permission.VIBRATE"/>

<uses-permissionandroid:name="android.permission.BLUETOOTH"/>

.......

<activityandroid:name="Settings"android:label="@string/settings_label"

android:taskAffinity="com.android.settings"

android:clearTaskOnLaunch="true"

android:launchMode="singleTop">

<intent-filter>

<actionandroid:name="android.intent.action.MAIN"/>

<actionandroid:name="android.settings.SETTINGS"/>

<categoryandroid:name="android.intent.category.DEFAULT"/>

<categoryandroid:name="android.intent.category.LAUNCHER"/>

</intent-filter>

</activity>

我们来看这段,Intent-filter这个是说预备接受哪些intent,android.intent.action.MAIN指的是这个Activity是此应用程序的进口。那么这个intent是谁发出来的呢?

我们可以看看code.

我们知道android再init最后面启动home服务,也就是我们这里所说的launcher.假如从homescreen这里点击 touchpad事件,这个event是如何传递给homescreen呢?

通常在home启动前,我们的各种服务就已经建立好了,包括了ActivityManagerService,home也是一个Activity。

publicvoidonItemClick(AdapterViewparent,Viewv,intposition,longid){

ApplicationInfoapp=(ApplicationInfo)parent.getItemAtPosition(position);

mLauncher.startActivitySafely(app.intent);

}

这一段就在launch里面的,这里我不得不说的是launcher的抽屉类,也就是按一下打开,在按一下关掉。

SlidingDrawer

<SlidingDrawer

android:id="@+id/drawer"

android:layout_width="fill_parent"

android:layout_height="fill_parent"

android:orientation="horizontal"

android:bottomOffset="4dip"

android:handle="@+id/all_apps"

android:content="@+id/content">

<com.android.launcher.HandleView

android:id="@id/all_apps"

android:layout_width="56dip"

android:layout_height="fill_parent"

android:background="@drawable/handle"

android:focusable="true"

android:clickable="true"

android:scaleType="center"

android:src="@drawable/handle_icon"

launcher:direction="vertical"/>

<com.android.launcher.AllAppsGridView

android:id="@id/content"

android:layout_width="fill_parent"

android:layout_height="fill_parent"

launcher:texture="@drawable/pattern_carbon_fiber_dark"

android:scrollbarStyle="outsideInset"

android:drawSelectorOnTop="false"

android:listSelector="@drawable/grid_selector"

android:nextFocusLeft="@id/all_apps"

android:nextFocusDown="@id/content"

android:nextFocusUp="@id/content"

android:nextFocusRight="@id/content"

android:verticalSpacing="10dip"

android:numColumns="5"/>

</SlidingDrawer>

SlidingDrawer有两个必须的元素,一个就是handle,一个是content,handle就是当你点击它的时候,content要么抽抽屉要么关抽屉,这里得handler

是一个自己创建的类叫做handleView.content是AllAppsGridView

我们往看看hanleView的代码

这里我们需要夸大的是用xml的方式天生的对象如何写构造函数,由于假如用findViewById这样的方式,没有构造函数的话,轻易返回null.

publicHandleView(Contextcontext){

super(context);

}

publicHandleView(Contextcontext,AttributeSetattrs){

this(context,attrs,0);

}

publicHandleView(Contextcontext,AttributeSetattrs,intdefStyle){

super(context,attrs,defStyle);

TypedArraya=context.obtainStyledAttributes(attrs,R.styleable.HandleView,defStyle,0);

mOrientation=a.getInt(R.styleable.HandleView_direction,ORIENTATION_HORIZONTAL);

a.recycle();

}

我们在使用xml天生布局的时候,系统会自动调用view的publicView(Contextcontext,AttributeSetattrs)这个构造器,attrs这个参数是有系统帮我们自动实现的。

handleView是在那里被调用的呢?实在launch.java的setupView函数中被调用的,context应该就是应用的地方调进的。我们看看launch.java

(Context字面意思上下文,位于frameworkpackage的android.content.Context中,实在该类为LONG型,类似Win32中的Handle句柄,很多方法需要通过Context才能识别调用者的实例,

比如说Toast的第一个参数就是Context,一般在Activity中我们直接用this代替,代表调用者的实例为Activity,

而到了一个button的onClick(Viewview)等方法时,我们用this时就会报错,

所以我们可能使用ActivityName.this来解决,主要原因是由于实现Context的类主要有Android特有的几个模型,Activity、Service以及BroadcastReceiver.)

setContentView(R.layout.Launcher).LauncherextendsActivity

在调用setConentView的时候往读些R.layout下面的xml文档,完成初始化UI的过程,slidingDraw就是在这个时候初始化的,那构造函数为什么要3个呢?

实在在这里第二个已经够了,

第一个是我们用new的时候需要调用的。第二个就是上面说的,第三个呢?SetContentView这个函数还有不同的参数调用,例如publicvoidsetContentView(Viewview,ViewGroup.LayoutParamsparams)这个就是会往调用第三个

Settheactivitycontenttoanexplicitview.Thisviewisplaceddirectlyintotheactivity'sviewhierarchy.Itcanitselfbeacomplexviewhierarhcy.

Parameters

重叠性的activity

对于drawer我们需要实现的是SlidingDrawer.OnDrawerOpenListener,onDrawerCloseListener,onDrawerScollListener的事件

具体我们可以往查看code

我们下来具体看看handleView都作了些什么

里面有focusSearch,onKeyDown,onKeyUp

focusSearch

这个函数主要是用来判定那些地方可以focus,根据不同的direction

这个函数主要是imageView需要

mDrawer=(SlidingDrawer)dragLayer.findViewById(R.id.drawer);

finalSlidingDrawerdrawer=mDrawer;

drawer.lock();

finalDrawerManagerdrawerManager=newDrawerManager();

drawer.setOnDrawerOpenListener(drawerManager);

drawer.setOnDrawerCloseListener(drawerManager);

drawer.setOnDrawerScrollListener(drawerManager);

/**

*Representsalaunchableapplication.Anapplicationismadeofaname(ortitle),

*anintentandanicon.

*/

是AllAppsGridView里面的元素,如何把这些content都找出来的呢?

/**

*LoadsthelistofinstalledapplicationsinmApplications.

*

*@returntrueiftheapplicationsloadermustbestarted

*(seestartApplicationsLoader()),falseotherwise.

*/

synchronizedbooleanloadApplications(booleanisLaunching,Launcherlauncher,

booleanlocaleChanged){

if(DEBUG_LOADERS)d(LOG_TAG,"loadapplications");

if(isLaunching&&mApplicationsLoaded&&!localeChanged){

mApplicationsAdapter=newApplicationsAdapter(launcher,mApplications);

if(DEBUG_LOADERS)d(LOG_TAG,"-->applicationsloaded,return");

returnfalse;

}

stopAndWaitForApplicationsLoader();

if(localeChanged){

dropApplicationCache();

}

if(mApplicationsAdapter==null||isLaunching||localeChanged){

mApplications=newArrayList<ApplicationInfo>(DEFAULT_APPLICATIONS_NUMBER);

mApplicationsAdapter=newApplicationsAdapter(launcher,mApplications);

}

mApplicationsLoaded=false;

if(!isLaunching){

startApplicationsLoaderLocked(launcher,false);

returnfalse;

}

returntrue;

}

PackageManagerandroid的安装包治理

finalIntentmainIntent=newIntent(Intent.ACTION_MAIN,null);

mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);

finalLauncherlauncher=mLauncher.get();

finalPackageManagermanager=launcher.getPackageManager();

finalList<ResolveInfo>apps=manager.queryIntentActivities(mainIntent,0);

这段code告诉我们如何用一个packageManager往查找那些包的治理,得到的相应的activityinfo,这个是从manifest.xml里面<activity>里面分离出来的。

finalHashMap<ComponentName,ApplicationInfo>appInfoCache=mAppInfoCache;

ComponentName的结构定义在content下面

ApplicationInfo继续ItemInfo

使用ArrayAdapter(数组适配器)顾名思义,需要把数据放进一个数组以便显示。

android.R.layout.simple_list_item_1是系统定义好的布局文件只显示一行文字

SimpleAdapter能定义各种各样的布局出来,可以放上ImageView(图片),还可以放上Button(按钮),CheckBox(复选框)

privatevoidbindDrawer(Launcher.DesktopBinderbinder,

ApplicationsAdapterdrawerAdapter){

mAllAppsGrid.setAdapter(drawerAdapter);

binder.startBindingAppWidgetsWhenIdle();

}

通过这个函数把LaunchermAllAppsGrid和LauncherModel的mApplicationsAdapter结合起来。

整个流程就是在DesktopItemLoaded结束后,就调用bindDrawer把GridView和content绑定,然后再GridView里面的getView函数往绘制

Launcher就分析到这里。




你可能感兴趣的:(launcher 分析)