
Launcher设计原理.doc
4页Home Screen的代码位于packages/apps/Launcher目录Launcher工程中的主要类如下:AddAdapter:添加桌面元素的适配器;AllAppsGridView:应用程序图标列表的主界面,继承GridView;ApplicationInfo:保存有应用程序的信息;ApplicationsAdapter:AllAppsGridView对应的Adapter;DeleteZone:Launcher的删除区域,继承ImageView;DragController:拖动控制接口;DragLayer:整个launcher的父节点,继承FrameLayout,实现接口DrayController;DragScrollerDragSource拖动源接口,定义了void onDropCompleted(View target, Boolean success);DropTarget:拖动目标,定义很多拖动过程需要的方法;HandleView:launcher抽屉的开关;ItemInfo:记录ITEM_TYPE_APPLICATION, ITEM_TYPE_USER_FOLDER, ITEM_TYPE_LIVE_FOLDER, ITEM_TYPE_WIDGET_SEARCH这些类型的Item;Launcher:整个launcher的程序的入口;LauncherModel:主要负责维护Launcher的状态和提供一些更新Launcher数据库状态的API;LauncherProvider:存储桌面上可以放置的几个对象,包括shortcut, search和clock等;WallpaperChooser:设置墙纸Workspace:控制桌面显示区域的layout,几个窗口就是它下面的子节点;从文件launcher.xml,workspace_screen.xml可获知Home Screen的UI结构如下图所示:(FrameLayout)com.android.launcher.Workspace(ViewGroup)SlidingDrawercom.android.launcher.DeleteZone(ImageView)com.android.launcher.CellLayout(ViewGroup)com.android.launcher.CellLayout(ViewGroup)com.android.launcher.HandleView(ImageView)com.android.launcher.AllAppsGridView(GridView) 整个homescreen是一个包含三个child view的FrameLayout(com.android.launcher.DragLayer)。
第一个child就是桌面com.android.launcher.Workspace,这个桌面又包含两个child每个child就对应一个桌面这就是在Android上看到的两个桌面每个桌面上放置下列对象:应用快捷方式、appwidget和folder第二个child是一个SlidingDrawer控件,这个控件由两个子控件组成一个是com.android.launcher.HandleView,就是android桌面下方的把手,当点击这个把手时,另一个子控件com.android.launcher.AllAppsGridView就会弹出,这个子控件列出系统中当前安装的所有类型为category.launcher的Activity第三个child是com.android.launcher.DeleteZone当用户在桌面上长按一个widget时,把手位置就会出现一个垃圾桶形状的控件,就是这个DeleteZone控件在虚拟桌面上可以摆放四种类型的对象:1、 ITEM_SHORTCUT,应用快捷方式;2、 ITEM_APPWIDGET,app widget;3、 ITEM_LIVE_FOLDER,文件夹;4、 ITEM_WALLPAPER,墙纸。
类AddAdapter(AddAdapter.java)列出了这四个类型对象当用户在桌面空白处长按时,下列函数序列被执行:Launcher::onLongClick->Launcher::showAddDialog->Launcher::showDialog(DIALOG_CREATE_SHORTCUT)->Launcher::onCreateDialog->Launcher::CreateShortcutcreateDialog这个函数创建一个弹出式对话框,询问用户是要添加什么(快捷方式、appwidget、文件夹或墙纸),其内容就来自AddAdapter类Favorites(LauncherSettings.java)和类LauncherProvider定义了一个content provider,用来存储桌面上可以放置的几个对象,包括shortcut, search和clock等类DesktopItemsLoader(LauncherModel.java)负责将桌面上所有的对象从content provider中提取 线程private ApplicationsLoader mApplicationsLoader(LauncherModel.java)负责从包管理器中获取系统中安装的应用列表。
之后显示在AllAppsGridView上)ApplicationsLoader::run实现:1、 通过包管理器列出系统中所有类型为Launcher,action为MAIN的activity;2、 对每一个Activity, a、 将Activity相关元数据信息,如title, icon, intent等缓存到mAppInfoCache; b、填充到ApplicationsAdapter 中填充过程中用到了一些小技巧,每填充4(UI_NOTIFICATION_RATE)个activity更新一下相应view 在Launcher::onCreate中,函数startLoaders被调用而该函数接着调用loadApplications和loadUserItems,分别获取系统的应用列表,以及显示在桌面上的对象列表(快捷方式、appwidget、folder等) Launcher上排列的所有应用图标由AllAppsGridView对象呈现这个对象是一个GridView其对应的Adapter是 ApplicationsAdapter,对应的model则是ApplicationInfo数组。
数组内容是由ApplicationsLoader(LauncherModel.java) 装载的发生切屏时的绘制和切换屏幕:在WorkSpace::onMeasure函数调用中有一个scrollTo函数,用于将屏幕移动到指定坐标位置程序初次启动时,显示默认第三屏便是在这里做了滚动操作,它会首先获得焦点由ViewGroup调用dispatchDraw()操作,进行绘制和draw动作的传递这里补充一个知识,除非ViewGroup本身有背景,否则调用onDraw是无效的 在dispatchDraw操作中,判断是否处于滑动状态,通过drawChild()来完成对当前主屏和滑动状态的下一主屏进行绘制否则,当切屏完成后,屏幕上不会有Widget或Shortcut,但是点击他们的位置却能启动相应程序 滑动屏幕时有两个个非常重要的函数即scrollTo、scrollBy,scrollTo, scrollBy其实都是在对View的内容进行移动在Touch Move中发生scrollBy后并不会去调用computeScroll(),反而在move结束,up事件中调用startSrcoll,开始不断调整mScrollX, mSrcollY,将当前的基准点重新置回标准的:0,0 320,0 640,0。
整体的绘制操作:接受onTouchEvent事件,当在移动中计算移动的距离,调整基准点并不停的绘制屏幕和移动壁纸,当touch结束后,通过startScroll将滑动完成,并将基准点置为标准点(在computeScroll中),更新重绘屏幕Launcher区别加载GoogleSearch和其它普通的AppWidget: 在Launcher中有一个static成员LauncherModel,它负责维护Launcher的状态和提供一些更新Launcher数据库状态的APILaunchModel中用不同的ArrayList记录 ItemInfo和LauncherAppWidgetInfo的信息(ITEM_TYPE_APPLICATION, ITEM_TYPE_USER_FOLDER, ITEM_TYPE_LIVE_FOLDER, ITEM_TYPE_WIDGET_SEARCH这些类型的Item都被记录在ItemInfo类型中)具体的加载过程大概是:在Launcher的onCreate和onResume中都调用了LauncherModel::loadUserItems方法之后的顺序是LauncherModel::loadUserItems->Launcher::onDesktopItemsLoaded->Launcher::bindDesktopItems-> Launcher ::startBindingItems->最后在Launcher:DesktopBinder::handleMessage 中通过Launcher::bindItems方法加载了Widget Search到workspace(控制桌面显示区域的class)上,而通过Launcher::startBindAppWidgets加载了普通的 AppWidgets。
Widget添加的过程:Launcher通过addSearch直接用inflate的方法产生一个GoogleSearchWidget的 View,并添加到workspace;而普通的AppWidget则是通过completeAddAppWidget中产生并添加一个 AppWidgetHostView来实现的Launcher启动时从数据库读取各种桌面物件信息到最后显示到屏幕桌面上的流程:启动Launcher后,系统会执行onCreate方法,方法中调用了本类的startLoaders()接着调用LauncherModel类中的loadUserItems()在方法中创建一个DesktopItemsLoader线程,start()启动线程,执行run方法1、 从数据库中取出桌面上所有对象:app,shortcut,search放在一个ArrayList
里面有一个接受消息的方法obtainMessage(),接收到消息后系统会自动调用DesktopBinder.handleMessage()在消息处理过程中会调用Launcher.bindItems()里面会调用WorkSpace.andInScreen。






![河南新冠肺炎文件-豫建科[2020]63号+豫建科〔2019〕282号](http://img.jinchutou.com/static_www/Images/s.gif)





