launcher架构解析

来源:互联网 发布:mac如何安装ae插件 编辑:程序博客网 时间:2024/05/16 14:59

做好launcher对其基本的架构了解是必须的,下面让我们了解下Launcher的组成和架构。

第一步,先看两张从网上找来的launcher的架构图。


第二张:


通过这两张图,简单的说下:

整个launcher,准确来说应该是homescreen更为合适,是一个包含三个child view的FrameLayout(com.android.launcher.DragLayer)。

第一个child就是桌面com.android.launcher.Workspace。这个桌面又包含5个child。每个child就对应一个桌 面。这就是你在Android上看到的五个桌面。每个桌面上可以放置下列对象:应用快捷方式,appwidget和folder。(第一张图应该是以前版本的,在2.2以前的版本应该是只有三个桌面,在2.3中,有五个桌面)

第二个child是一个SlidingDrawer控件,这个控件由两个子控件组成。一个是 com.android.launcher.HandleView,就是Android桌面下方的把手,当点击这个把手时,另一个子控 件,com.android.launcher.AllAppsGridView就会弹出,这个子控件列出系统中当前安装的所有类型为 category.launcher的Activity。

第三个child是com.android.launcher.DeleteZone。当用户在桌面上长按一个widget时,把手位置就会出现一个垃圾桶形状的控件,就是这个控件。(其实在2.2以后的版本中,在左下方和右下方添加了页面标记,来告诉用户当前在哪个桌面,其代码在launcher.xml代码中,

[html] view plaincopy
  1. <ImageView  
  2.         android:id="@+id/previous_screen"  
  3.         android:layout_width="93dip"  
  4.         android:layout_height="@dimen/button_bar_height"  
  5.         android:layout_gravity="bottom|left"  
  6.         android:layout_marginLeft="6dip"  
  7.   
  8.         android:scaleType="center"  
  9.         android:src="@drawable/home_arrows_left"          
  10.         android:onClick="previousScreen"  
  11.         android:focusable="true"  
  12.         android:clickable="true" />  
  13.   
  14.     <ImageView  
  15.         android:id="@+id/next_screen"  
  16.         android:layout_width="93dip"  
  17.         android:layout_height="@dimen/button_bar_height"  
  18.         android:layout_gravity="bottom|right"  
  19.         android:layout_marginRight="6dip"  
  20.         android:scaleType="center"  
  21.         android:src="@drawable/home_arrows_right"  
  22.         android:onClick="nextScreen"  
  23.         android:focusable="true"  
  24.         android:clickable="true" />  
下面就是launcher中主要类的简介:
AddAdapter:添加桌面元素的适配器,维护了live fold  , widget , shortcut , wallpaper 4个ListItem , 长按桌面会显示该列表
AllAppsGridView:Icon列表的的主界面,继承gridView。

ApplicationInfo:一个可启动的应用。

ApplicationsAdapter:gridview的adapter。

BubbleTextView:一个定制了的textview,主要用于显示应用图标。


DeleteZone:luancher的删除区域,继承ImageView。在平时是出于隐藏状态,在将item长按拖动的时候会显示出来,如果将item拖动到删除框位置时会删除item。   DeleteZone实现了DropTarget和DragListener两个接口。


DragController:拖动控制接口。为Drag定义的一个接口。包含一个接口,两个方法和两个静态常量。接口为DragListener(包含onDragStart(),onDragEnd()两个函数),onDragStart()是在刚开始拖动的时候被调用,onDragEnd()是在拖动完成时被调用。在launcher中典型的应用是DeleteZone,在长按拖动item时调用onDragStart()显示,在拖动结束的时候onDragEnd()隐藏。两个函数包括startDrag()和setDragItemInfo().startDrag()用于在拖动是传递要拖动的item的信息以及拖动的方式,setDragItemInfo()用于传递item的参数信息(包括位置以及大小)。两个常量为DRAG_ACTION_MOVE,DRAG_ACTION_COPY来标识拖动的方式,DRAG_ACTION_MOVE为移动,表示在拖动的时候需要删除原来的item,DRAG_ACTION_COPY为复制型的拖动,表示保留被拖动的item。


DragLayer:整个launcher的父节点,继承FrameLayout,实现接口DrayController,是内部支持拖拽的viewgroup。DragLayer实际上也是一个抽象的界面,用来处理拖动和对事件进行初步处理然后按情况分发下去,角色是一个controller。它首先用onInterceptTouchEvent(MotionEvent)来拦截所有的touch事件,如果是长按item拖动的话不把事件传下去,直接交由onTouchEvent()处理,这样就可以实现item的移动了,如果不是拖动item的话就把事件传到目标view,交有目标view的事件处理函数做相应处理。如过有要对事件的特殊需求的话可以修改onInterceptTouchEvent(MotionEvent)来实现所需要的功能。


DragSource:拖动源接口,定义了void onDropCompleted(View target, boolean success)。


DropTarget:拖动目标,定义很多拖动过程需要的方法:onDrop,onDragEnter,onDragOver,onDragExit,acceptDrop。

FastBitmapDrawable:工具

Folder:Icons的集合

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

FolderInfo: ItemInfo子类

HandleView:launcher抽屉的开关,不过在android2.2已经没用抽屉了。

InstallShortcutReceiver,UninstallShortcutReceiver:一个broadcastrecier

ItemInfo:代表Launcher中一个Item(例如folder)对item的抽象,所有类型item的父类,item包含的属性有id(标识item的id),cellX(在横向位置上的位置,从0开始),cellY(在纵向位置上的位置,从0开始) ,spanX(在横向位置上所占的单位格),spanY(在纵向位置上所占的单位格),screen(在workspace的第几屏,从0开始),itemType(item的类型,有widget,search,application等),container(item所在的)。

Launcher:整个launcher的程序的入口,代码量最大的一个文件。

LauncherApplication:在VM中设置参数

LauncherAppWidgetHost,LauncherAppWidgetHostView,:Widget相关

LauncherModel: MVC中的M,里面有许多封装的对数据库的操作。包含几个线程,其中最主要的是ApplicationsLoader和DesktopItemsLoader。ApplicationsLoader在加载所有应用程序时使用,DesktopItemsLoader在加载workspace的时候使用。其他的函数就是对数据库的封装,比如在删除,替换,添加程序的时候做更新数据库和UI的工作。

LauncherProvider:launcher的数据库,一个contentprovider里面存储了桌面的item的信息。在创建数据库的时候会loadFavorites(db)方法,loadFavorites()会解析xml目录下的default_workspace.xml文件,把其中的内容读出来写到数据库中,这样就做到了桌面的预制。

LauncherSettings:设置相关的工具,数据库项的字符串定义,另外在这里定义了container的类型,还有itemType的定义,除此还有一些特殊的widget(如search,clock的定义等)的类型定义。

LiveFolder,LiveFolderAdapter,LiveFolderIcon,LiveFolderInfo: livefolder相关

Search: 搜索

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

Utilities:小工具

WallpaperChooser:选择wallpaper的activity

Workspace:整个界面layout,几个窗口就是他下面的子节点。

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


在桌面中,有一下四种类型的对象:
1. ITEM_SHORTCUT,应用快捷方式,对应实现布局文件R.layout.application
2. ITEM_APPWIDGET,app widget  桌面组件
3. ITEM_LIVE_FOLDER,文件夹

     --UserFolderInfo 对应实现布局文件R.layout.folder_icon
     --LiveFolderInfo 对应实现布局文件R.layout.live_folder_icon
4. ITEM_WALLPAPER,墙纸。


下面,我们详细的来说一下launcher里面的详细功能:

1.DragLayer--DragLayer继承FrameLayout,并在此基础上组合了DragController实现拖放功能,DragLayer主要监听下面两个用户事件onInterceptTouchEvent和onTouchEvent
并交给DragController进行处理,DragController根据是否在拖放中等信息控制控件拖放过程处理。DragLayer 是Launcher这个activity的顶层view,其实在Launcher2这个应用只有Laucher.java这么一个activity。

 

2.DeleteZone--

[html] view plaincopy
  1. <com.android.launcher2.DeleteZone  
  2.         android:id="@+id/delete_zone"  
  3.         android:layout_width="@dimen/delete_zone_size"  
  4.         android:layout_height="@dimen/delete_zone_size"  
  5.         android:paddingTop="@dimen/delete_zone_padding"  
  6.         android:layout_gravity="bottom|center_horizontal"  
  7.   
  8.         android:scaleType="center"  
  9.         android:src="@drawable/delete_zone_selector"  
  10.         android:visibility="invisible"  
  11.         launcher:direction="horizontal"  
  12.         />  

在launcher.xml中,可以发现,DeleteZone默认是不显示的android:visibility="invisible",但是我们每次开始拖放图标的时候DeleteZone就显示了,这个功能是如何实现的呢?在代码中可以发现DeleteZone实现了DragController.DragListener接口,

[html] view plaincopy
  1. public class DeleteZone extends ImageView implements DropTarget, DragController.DragListener   

DragListener提供两个接口方法,
onDragStart:隐藏把手,显示DeleteZone
onDragEnd:显示把手,隐藏DeleteZone

在DeleteZone中,看一下代码:

[java] view plaincopy
  1. public void onDragStart(DragSource source, Object info, int dragAction) {  
  2.         final ItemInfo item = (ItemInfo) info;  
  3.         if (item != null) {  
  4.             mTrashMode = true;  
  5.             createAnimations();  
  6.             final int[] location = mLocation;  
  7.             getLocationOnScreen(location);  
  8.             mRegion.set(location[0], location[1], location[0] + mRight - mLeft,  
  9.                     location[1] + mBottom - mTop);  
  10.             mDragController.setDeleteRegion(mRegion);  
  11.             mTransition.resetTransition();  
  12.             startAnimation(mInAnimation);  
  13.             mHandle.startAnimation(mHandleOutAnimation);  
  14.             setVisibility(VISIBLE);  
  15.         }  
  16.     }  
  17.   
  18.     public void onDragEnd() {  
  19.         if (mTrashMode) {  
  20.             mTrashMode = false;  
  21.             mDragController.setDeleteRegion(null);  
  22.             startAnimation(mOutAnimation);  
  23.             mHandle.startAnimation(mHandleInAnimation);  
  24.             setVisibility(GONE);  
  25.         }  
  26.     }  

分别在开始DragController开始拖放和结束拖放的时候被调用.
另外DeleteZone实现了DropTarget接口的onDrop方法

[java] view plaincopy
  1. public void onDrop(DragSource source, int x, int y, int xOffset, int yOffset,  
  2.             DragView dragView, Object dragInfo) {  
  3.         final ItemInfo item = (ItemInfo) dragInfo;  
  4.   
  5.         if (item.container == -1return;  
  6.   
  7.         if (item.container == LauncherSettings.Favorites.CONTAINER_DESKTOP) {  
  8.             if (item instanceof LauncherAppWidgetInfo) {  
  9.                 mLauncher.removeAppWidget((LauncherAppWidgetInfo) item);  
  10.             }  
  11.         } else {  
  12.             if (source instanceof UserFolder) {  
  13.                 final UserFolder userFolder = (UserFolder) source;  
  14.                 final UserFolderInfo userFolderInfo = (UserFolderInfo) userFolder.getInfo();  
  15.                 // Item must be a ShortcutInfo otherwise it couldn't have been in the folder  
  16.                 // in the first place.  
  17.                 userFolderInfo.remove((ShortcutInfo)item);  
  18.             }  
  19.         }  
  20.         if (item instanceof UserFolderInfo) {  
  21.             final UserFolderInfo userFolderInfo = (UserFolderInfo)item;  
  22.             LauncherModel.deleteUserFolderContentsFromDatabase(mLauncher, userFolderInfo);  
  23.             mLauncher.removeFolder(userFolderInfo);  
  24.         } else if (item instanceof LauncherAppWidgetInfo) {  
  25.             final LauncherAppWidgetInfo launcherAppWidgetInfo = (LauncherAppWidgetInfo) item;  
  26.             final LauncherAppWidgetHost appWidgetHost = mLauncher.getAppWidgetHost();  
  27.             if (appWidgetHost != null) {  
  28.                 final int appWidgetId = launcherAppWidgetInfo.appWidgetId;  
  29.                 // Deleting an app widget ID is a void call but writes to disk before returning  
  30.                 // to the caller...  
  31.                 new Thread("deleteAppWidgetId") {  
  32.                     public void run() {  
  33.                         appWidgetHost.deleteAppWidgetId(launcherAppWidgetInfo.appWidgetId);  
  34.                     }  
  35.                 }.start();  
  36.             }  
  37.         }  
  38.         LauncherModel.deleteItemFromDatabase(mLauncher, item);  
  39.     }  

当把图标拖放到DeleteZone,就会调用DeleteZone,实现的onDrop方法对应用图标进行删除处理。

 

3.屏幕左右移动按钮,就是使用的ImageView,

[html] view plaincopy
  1. <ImageView  
  2.         android:id="@+id/previous_screen"  
  3.         android:layout_width="93dip"  
  4.         android:layout_height="@dimen/button_bar_height"  
  5.         android:layout_gravity="bottom|left"  
  6.         android:layout_marginLeft="6dip"  
  7.   
  8.         android:scaleType="center"  
  9.         android:src="@drawable/home_arrows_left"          
  10.         android:onClick="previousScreen"  
  11.         android:focusable="true"  
  12.         android:clickable="true" />  
  13.   
  14.     <ImageView  
  15.         android:id="@+id/next_screen"  
  16.         android:layout_width="93dip"  
  17.         android:layout_height="@dimen/button_bar_height"  
  18.         android:layout_gravity="bottom|right"  
  19.         android:layout_marginRight="6dip"  
  20.         android:scaleType="center"  
  21.         android:src="@drawable/home_arrows_right"  
  22.         android:onClick="nextScreen"  
  23.         android:focusable="true"  
  24.         android:clickable="true" />  

注意三点,

--1.桌面左右移动时Drawable的变换,变换图标列表可查看home_arrows_right.xml
,ImageView通过把drawable传递给worksapce,当桌面切换时通过调用Drawable.setLevel()方法实现不同图标显示。
--2.当点击实现左右桌面切换,查看上面的布局文件中android:onClick="previousScreen",该属性定义了一个 onClick事件响应函数,在Launcher.java中的788行。
[html] view plaincopy
  1. @SuppressWarnings({"UnusedDeclaration"})  
  2.     publicvoid previousScreen(View v) {  
  3.         if(!isAllAppsVisible()) {  
  4.             mWorkspace.scrollLeft();  
  5.         }  
  6.     }  

--3.在(Launcher.setupViews)中添加了长按事件OnLongClickListener有当长按会执行launcher.onlongclick方法,方法执行显示5个桌面的预览微缩图显示。

 

4.RelativeLayout--android:id="@+id/all_apps_button_cluster",如前面截图右边灰色竖状条,它是一个相对布局对象,上面承载了三个view
中间是一个HandleView,是一个进入allappview的按钮,HandleView的左面是拨号,右面是浏览器两个ImageView。
        --HandleView
                --1.点击事件 传递给Launcher.onClick进行处理 显示应用菜单view
                --2.长按事件 传递给Launcher.onLongClick进行处理,方法执行显示5个桌面的预览微缩图显示
        --拨号或者浏览器
                --onClick响应:android:onClick="launchHotSeat"

5.Workspace--用户桌面包括5个workspace_screen,launcher:defaultScreen="2"在前面已经说过,表示默认桌面是第三个。

workspace继承了viewgroup,5个workspace_screen作为它的child,值得注意它只接收CellLayout类型的child,workspace重写了addview函数,添加了非CellLayout的child将抛异常
--Workspace长按事件由launcher.onLongClick来监听
--Workspace实现了DropTarget, DragSource两个接口,意味着Workspace既是拖放源,又是拖放目的地
--Workspace实现DragScroller接口,DragScroller接口提供两个方法
    void scrollLeft()和void scrollRight()在拖放过程被DragController调用实现桌面的左右滚动。
  --CellLayout Workspace下的一个桌面布局,CellLayout也是ViewGroup的子类,

  Workspace下有5个CellLayout顺序排列,Workspace下布局文件:android:scrollbars="horizontal"决定了5个CellLayout排列是横向还是纵向的

[html] view plaincopy
  1. <com.android.launcher2.CellLayout  
  2.     xmlns:android="http://schemas.android.com/apk/res/android"  
  3.     xmlns:launcher="http://schemas.android.com/apk/res/com.android.launcher"  
  4.   
  5.     android:layout_width="match_parent"  
  6.     android:layout_height="match_parent"  
  7.     android:hapticFeedbackEnabled="false"  
  8.     launcher:cellHeight="@dimen/workspace_cell_height"//每个cell的高度  
  9.     launcher:longAxisStartPadding="8dip"//cell距离父view CellLayout左边距  
  10.     launcher:longAxisEndPadding="78dip"//cell距离父view CellLayout右边距  
  11.     launcher:shortAxisStartPadding="0dip"//cell距离父view CellLayout上边距  
  12.     launcher:shortAxisEndPadding="0dip"//cell距离父view CellLayout下边距  
  13.     launcher:shortAxisCells="4"//CellLayout cells行数  
  14.     launcher:longAxisCells="4"//CellLayout cells列数 />  

当纵向的控件不够cells排列时,cell将产生重叠,横向不产生重叠,横向每个cell间隔至少为0      

  --CellLayout覆盖重新实现了onMeasure方法,和onlayout方法,它限定了child view 使用的布局参数类型为CellLayout.LayoutParams因此企图通过修改

        workspace_screen.xml来改变它的桌面布局是不会得以成功的,你必须修改CellLayout类
        --CellLayout.LayoutParams说明,CellLayout.LayoutParams下有几个成员需要说明一下
                --cellX:该child view占用的第几列的cell(若横向占用多个cell,表示最左边的cellx)
                --cellY: 该child view占用的第几行的cell(若纵向占用多个cell,表示最上边的celly)
                --cellHSpan:横向跨越的列数
                --cellVSpan: 纵向跨越行数
                --isDragging:该child是否正在被拖动
                --regenerateId:是否重新生成view id


最后以网上淘来的launcher类的关系来结束这篇文章:


0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 ipad电源键坏了怎么办 华为平板死机黑屏了怎么办 苹果4s锁屏键坏了怎么办 平板电脑密码锁忘记密码怎么办 苹果平板电脑密码锁忘记密码怎么办 平板电脑密码锁密码锁死怎么办 小米平板黑屏按键亮怎么办 小米平板黑屏没反应怎么办 小米平板一刷黑屏了怎么办 小米4卡死了怎么办啊 苹果平板电脑开不了机怎么办 ipad开不了机怎么办都是黑屏 手机突然黑屏了死机状态怎么办 苹果平板死机不能重启怎么办 韩众平板死机了怎么办 苹果平板输入密码多次停用怎么办 ld密码被停用了怎么办 档案被自己丢了怎么办 手机在厂里丢了怎么办 在厂里借工具丢了怎么办 导出的考勤没有姓名怎么办 退休时档案丢了怎么办 职工与企业没有劳资怎么办 去大学报道的档案袋丢失怎么办 档案入学毕业年份写错怎么办 从事业单位辞职后人事档案怎么办 老师辞职不给批怎么办 公办教师去私立学校档案怎么办 辞职后档案不给怎么办 档案不小心拆了怎么办 退休职工档案年龄有涂改怎么办 养老金原始档案找不到怎么办退休 寄辞职信不接收怎么办 公司不给办离职怎么办 离职手续表填写错误怎么办 退货少退了个配件怎么办 小米8拖影严重怎么办 被兼职中介骗了怎么办 被兼职中介坑了怎么办 人在工厂宿舍死了怎么办 事业单位在编人员开除后社保怎么办