Launcher介绍总结



一、主要文件和类
1.Launcher.java:launcher中主要的activity。

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

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

4.LauncherModel.java:辅助的文件。里面有许多封装的对数据库的操作。loadAndBindAllApps加载所有应用程序,loadAndBindWorkspace加载workspace。其他的函数就是对数据库的封装,比如在删除,替换,添加程序的时候做更新数据库和UI的工作。

5.Workspace.java:抽象的桌面,继承自ViewGroup,是一个子view。由N个celllaout组成,从cellLayout更高一级的层面上对事件的处理。

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

7.CellLayout.java:组成workspace的view,继承自viewgroup,既是一个dragSource,又是一个dropTarget,可以将它里面的item拖出去,也可以容纳拖动过来的item。在workspace_screen里面定了一些它的view参数。

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

9.UserFolder.java: 用户创建的文件夹。可以将item拖进文件夹,单击时打开文件夹,长按文件夹上面标题处可以重命名文件夹。

10.LiveFolder.java:系统自带的文件夹。从系统中创建出的如联系人的文件夹等。

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

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

主要布局文件介绍:
packages/apps/Launcher2/res/layout-port/launcher.xml
总布局文件竖屏,主要显示workspaceHandleView等按键
/packages/res/Launcher2/res/workspase_screen.xml
cell的数量及显示大小
/packages/res/Launcher2/res/layout/AllAppSpace.xml
显示allapp界面布局(注意不是all_apps_2d.xml)
/packages/res/Launcher2/res/xml/default_workspace.xml
显示在workspace上默认的控件位置设置
/packages/res/Launcher2/res/xml/workspace_settings.xml
Workspace界面一些特效设置选项
/packages/res/Launcher2/res/layout/allapp_workspace_screen.xml
All app界面app布局显示
/packages/apps/Launcher2/res/layout-port/all_apps_horizontal.xml
All app界面布局显示(包括指示图标与app布局)


二、LauncherApplication全局数据初始化过程
LauncherApplication是Application的子类,是整个程序的入口。因此,一些全局信息的初始化和保存工作就放到这里执行。包括屏幕大小,像素密度信息的获取,以及
BroadcastReceiver和ContentObserver的注册都在整个程序的开始就完成。
1、VMRuntime.getRuntime().setMinimumHeapSize(4 * 1024 * 1024)
设置运行最小堆内存
2、mIconCache = new IconCache()
实例化图标缓存区的对象
3、mModel = new LauncherModel()
实例化一个LauncherModel对象,这个类是保存Launcher的内存启动状态,更新Launcher的数据库的作用
4、IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
注册监听,应用package增加,删除,改变的监听。
5、filter = new IntentFilter()
注册application是否可用,方向改变的监听
6、 ContentResolver resolver = getContentResolver(),resolver.registerContentObserver(LauncherSettings.Favorites.CONTENT_URI, true, mFavoritesObserver)。
注册favorites应用程序数据库改变的监听
7、初始化all app信息
数据库mFavoritesObserver监听内部类
privatefinal ContentObserver mFavoritesObserver = new ContentObserver(new Handler()) {
@Override
publicvoid onChange(boolean selfChange) {
mModel.startLoader(LauncherApplication.this, false);
}
};


三、Launcher.java的onCreate()所有界面初始化过程
LauncherApplication.onCreate()方法启动完成后,接着开始调用Launcher.java的onCreate()方法之后开始初始化Launcher。

可以将Launcher.onCreate()所执行的操作大概分为以下几步:

1、LauncherAppliaction.setLauncher()。
此方法中得到一个LauncherModel对象的引用,LauncherModel这个类中有个回调接口。对LauncherModel进行初始化的时候
public void initialize(Callbacks callbacks){
synchronized(mLock) {
mCallbacks= new WeakReference(callbacks);
}
}
由于Launcher实现了Callback接口。在mModel中,将传入的Launcher对象向下转型为Callback赋值给mCallbacks变量。并在LauncherModel中获得了一个Callbacks的软引用。通过这一过程,将Launcher对象作为Callback与mModel进行绑定,当mModel后续进行操作时,Launcher可以通过回调得到结果。

2、AppWidgetHost.startListening(),
作用:帮助Launcher管理AppWidget,并且能够捕获长按事件,使得应用可以正常的删除、添加AppWidget。通过调用mAppWidgetHost.startListening()方法,开启监听。

3、checkForLocaleChange()
检查本地文件的配置与当前设备的配置是否一致,如果不一致,则更新配置,并且清空IconCache,因为配置的改变可能会改变语言环境,所以需要清空IconCache中的内容重新加载。

4、setupViews(),对所有的UI控件进行加载和配置
DragLayer dragLayer = (DragLayer)findViewById(R.id.drag_layer);
dragLayer.setDragController(dragController);
DragLayer继承自FrameLayout,是整个Launcher的根容器。当快捷图标或者AppWidget被拖拽时,事件的处理就在DragLayer进行操作的。DragController可以帮助实现拖拽。

在loadHotseats(); 中,加载hotseats 增加intent意图启动的activity。

dragController.setDragScoller(workspace);
dragController.setDragListener(deleteZone);
dragController.setScrollView(dragLayer);
dragController.setMoveTarget(workspace);
对workspace,deleteZone进行拖拽,move等动作的监听。
dragController.addDropTarget(workspace);
dragController.addDropTarget(deleteZone);
在workspace,deleteZone中注册增加目标如application,appwidget等控件的监听。

5、registerContentObservers(),设置内容监听器
6、LauncherModel.startLoader(),为Launcher加载Workspace和AllApps中的内容
if(!mRestoring) {
//mModel.setmAppsLoading(true);
mModel.startLoader(this, true);
}
之后调用
public void startLoader(Context context,boolean isLaunching,boolean onlyLoadAllApp) {
……
mLoaderTask =new LoaderTask(context, isLaunching,onlyLoadAllApp);
sWorker.post(mLoaderTask);
}
说明:mModel.startLoader(。。,。。)是开启一个线程,设置线程的优先级NORM_PRIORITY,开始load桌面图标对应的数据库,这个过程是和Launcher.onCreate()同时进行的;
mModel.startLoader(。。,。。) àLoaderTask.java的run()方法,加载桌面图标对应的数据库的值,这些值能把这些图标显示在workspace屏幕上。
public voidrun() {
… …
keep_running: {
……
if (loadWorkspaceFirst) {
if (DEBUG_LOADERS)Log.d(TAG, "step 1: loading workspace");
loadAndBindWorkspace();
} else {
if (DEBUG_LOADERS)Log.d(TAG, "step 1: special: loading all apps");
loadAndBindAllApps();
}
if (mStopped) {
break keep_running;
}
……
waitForIdle();
// second step
if(!mOnlyLoadAllApp){// here , we do not load other ,only All_app because of All_APP Switch
if (loadWorkspaceFirst) {
if (DEBUG_LOADERS) Log.d(TAG, "step 2:loading all apps");
loadAndBindAllApps();
} else {
if (DEBUG_LOADERS) Log.d(TAG, "step 2:special: loading workspace");
loadAndBindWorkspace();
}
}
}……
}

加载的工作由两部分组成,第一部分是为Workspace加载内容,第二部分则是为AllApps加载内容。每一部分的加载又可以分为两个步骤:

1、由LauncherModel完成,主要工作是从数据库中读取信息,并且按类别将内容项分装到不同的数据结构中。
2、由Launcher来完成,通过LauncherModel.Callbacks接口定义的回调方法,从LauncherModel
中获取的数据,将其显示到桌面。

第一部分在loadWorkspace中,从ContentProvider获取指定URI中的数据,并将它们分类存放到指定的数据结构中。分类的标准有两条:1、item的类型。包括ITEM_TYPE_APPLICATION,ITEM_TYPE_SHORTCUT ,ITEM_TYPE_USER_FOLDER,ITEM_TYPE_APPWIDGET,ITEM_TYPE_LIVE_FOLDER五类。2、item所属的容器。包括CONTAINER_DESKTOP
以及其它(主要指文件夹)。

LauncherModel在读取完数据之后,通过LauncherModel.bindWorkspace()将数据传给到Launcher。进入LauncherModel.bindWorkspace()中

在bindWorkspace中,
Launcher的内容绑定分为五步:分别对应着startBinding()、bindItems()、bindFolders()、bindAppWidgets()、finishBindingItems()的调用。

第二部分AllApps的内容加载loadAndBindAllApps
首先是查询所有的App了,通过向PackagedManager发送指定的Intent就能够获得安装好的应用的信息。查询完毕之后,将数据封装到ArrayList对象中,然后通过Callbacks.bindAllApplication()或Callbacks.bindAppsAdded()将数据传给Launcher。

在这个方法中,还涉及到app排序问题,
Collections.sort(apps,newResolveInfo.DisplayNameComparator(packageManager));
至此All Apps页面的加载完成。

其中all app布局显示在从Callbacks.bindAllApplications –> setApps() à addApps()à
initLayout() à setViewInLayout()(其中通过mHandler.sendEmptyMessage(SORTFINISH); ) à
handleMessage() –> 显示屏上app如何布局


四、workspace触摸事件处理过程
在Launcher的View tree中,从上到下的主要的节点有,DragLayer,Workspace,
CellLayout。DragLayer层的主要任务是负责对图标和AppWidget进行拖拽,Workspace则主要负责左右滑动,CellLayout则用于容纳各种桌面的快捷方式

桌面滑动功能主要分两步:1、在onInterceptTouchEvent中进行拦截。2、在onTouchEvent中进行滑动。
在workspace.java中的onInterceptTouchEvent()函数中中
TOUCH_STATE_SCROLLING状态—> 正在滑动
TOUCH_STATE_REST状态—> 初始化状态,未滑动
acquireVelocityTrackerAndAddMovement(ev)获取速度跟踪器,记录各个时刻的速度。并且添加当前的MotionEvent以记录更行速度值。
public booleanonInterceptTouchEvent(MotionEvent ev) {
……
returnmTouchState != TOUCH_STATE_REST;
}
只有进入了滑动状态,才进行拦截,进入onTouchEvent执行滑动操作。当mTouchState != TOUCH_STATE_REST时,就说明没有进入滑动状态。(因为returntrue)。
当mTouchState==TOUCH_STATE_REST时,不需要任何滑动操作,将MotionEvent向子View传递。
开始桌面静止,则mTouchState==TOUCH_STATE_REST,触发switch分支中
MotionEvent.ACTION_DOWN的代码。记录按下点的坐标,设置mAllowLongPress=true。由于mTouchState=TOUCH_STATE_REST,所以动作被传向了子View。接下来,在长按事件被触发之前移动手指则会在代码中调用enableChildrenCache(mCurrentScreen - 1,mCurrentScreen + 1)来决定是否进入滑动状态。进入滑动状态之后mTouchState的值就变为TOUCH_STATE_SCROLLING,然后onTouchEvent中的操作就会被用,开始滑动。

在workspace中的onTouchEvent()函数,对接受到的不同的事件进行了分类的处理,大致可以将功能分类为:
1、当接受到ACTION_DOWN时,若滑动正在进行,则停止。
2、当接受到ACTION_MOVE时,根据当前的状态调用scrollBy进行滑动。
3、当接受到ACTION_UP时,根据当前所滑动的位移和速度,判断松手后进入到哪一个分屏。


在Workspace.Java类实现,相关方法有:
1) computeScroll():重写了父类的computeScroll();主要功能是计算拖动的位移量、更新背景、设置要显示的屏幕(setScreen(mCurrentScreen); )

2) dispatchDraw():重写了父类的dispatchDraw();主要功能是绘制指定的屏幕,可以绘制当前一屏,也可以绘制当前屏幕和下一屏幕,也可以绘制所有的屏幕,这儿的绘制指显示屏幕上的child(例如:app、folder、Wiget)。

3) onMeasure():重写了父类的onMeasure();主要功能是设置屏幕的显示大小。由每个child的measure()方法设置。

4) onLayout():重写了父类的onLayout();主要功能是设置屏幕的显示位置。由child的layout()方法设置。



五、Drop& Drag模型:DragController.java处理拖曳动作的函数
DragSource:可以拖动的对象来源的容器。
在launcher中主要有AllAppGridView,workspace等。
将调用此接口:voidonDropCompleted(View target, boolean success,int x,int y);

DropTarget:可以放置被拖动的对象的容器。
在launcher中有folder,workspace等,一个View既可以是Dragsource也可以是DropTarget。

主要包含以下几个接口:
boolean acceptDrop(DragSource source, intx, int y, int xOffset, int yOffset, Object dragInfo);
acceptDrop函数用来判断dropTarget是否可以接受item放置在自己里面。

void onDragEnter(DragSource source, int x,int y, int xOffset, int yOffset, Object dragInfo);
onDragEnter是item被拖动进入到一个dropTarget的时候的回调。

void onDragOver(DragSource source, int x,int y, int xOffset, int yOffset, Object dragInfo);
onDragOver是item在上一次位置和这一次位置所处的dropTarget相同的时候的回调。

void onDragExit(DragSource source, int x,int y, int xOffset, int yOffset, Object dragInfo);
onDragExit是item被拖出dropTarget时的回调。

boolean onDrop(DragSource source, int x,int y, int xOffset, int yOffset, Object dragInfo);
onDrop是item被放置到dropTarget时的回调。

例如:onDrop在drop()方法中被调用。
Drop()被DragController.java中的onInterceptTouchEvent()或onTouchEvent()调用
privateboolean drop(float x, float y) {
final int[] coordinates = mCoordinatesTemp;
DropTarget dropTarget = findDropTarget((int) x, (int) y,coordinates);
Log.d(TAG, "dropTarget exist is "+ (dropTarget!=null));
if (dropTarget != null) {
dropTarget.onDragExit(mDragSource, coordinates[0], coordinates[1],
(int) mTouchOffsetX,(int) mTouchOffsetY, mDragView, mDragInfo);
//判断dropTarget是否接受接受item放置
if (dropTarget.acceptDrop(mDragSource, coordinates[0],coordinates[1],
(int) mTouchOffsetX,(int) mTouchOffsetY, mDragView, mDragInfo)) {
dropTarget.onDrop(mDragSource,coordinates[0], coordinates[1],
(int) mTouchOffsetX,(int) mTouchOffsetY, mDragView, mDragInfo);
mDragSource.onDropCompleted((View) dropTarget, true);
return true;
} else {
mDragSource.onDropCompleted((View) dropTarget, false);
return true;
}
}
return false;
}

六、 Launcher 中 View 、ViewGroup事件处理:
事件处理主要方法:
1)public booleandispatchTouchEvent(MotionEvent ev)这个方法用来分发TouchEvent
2)public booleanonInterceptTouchEvent(MotionEvent ev) 这个方法用来拦截TouchEvent(只有ViewGroup中有此函数)
3)public booleanonTouchEvent(MotionEvent ev) 这个方法用来处理TouchEvent(ViewGroup与View中都有)
需要注意以下几点:
1、onInterceptTouchEvent()返回true,那么这个方法只会拦截动作ACTION_DOWN。
2、onInterceptTouchEvent()负责事件分发(事件传递方向),决定了Touch事件是否要向它包含的子View继续传递。
3、onTouchEvent()负责事件处理。决定了事件及后续事件是否继续向上传递。


当TouchEvent发生时,首先Activity将TouchEvent传递给最顶层的View, TouchEvent最先到达最顶层 view 的dispatchTouchEvent ,然后由dispatchTouchEvent 方法进行分发,

1)如果dispatchTouchEvent返回true ,则交给这个view(本view)的onTouchEvent处理,

2)如果dispatchTouchEvent返回 false ,则交给这个 view(本view) 的 interceptTouchEvent 方法来决定是否要拦截这个事件,

3)如果interceptTouchEvent 返回 true ,也就是拦截掉了,则交给它的 onTouchEvent 来处理,
(本ViewGroup的interceptTouchEvent 只能收到down事件,本ViewGroup的onTouchEvent能收到down,move,up事件,子view不能收到事件)

4)如果interceptTouchEvent返回 false ,那么就传递给子 view ,由子 view 的 dispatchTouchEvent 再来开始这个事件的分发。(本ViewGroup的onInterceptTouchEvent能收到down,move,up事件,本ViewGroup的onTouchEvent没有收到事件;之后(指onInterceptTouchEvent接受所有事件后)子view的onTouchEvent能收到up,move,down事件)

5)如果事件传递到某一层的子 view 的onTouchEvent 上了,这个方法返回了 false ,那么这个事件会从这个 view 往上传递,都是 onTouchEvent 来接收。
(本view的onTouchEvent只能收到down事件,不能收到move,up事件)

6)而如果传递到最上面的onTouchEvent 也返回 false 的话,这个事件就会“消失”,而且接收不到下一次事件。

7)如果最终需要处理事件的view 的onTouchEvent()返回了true,那么后续事件将可以继续传递给该view的onTouchEvent()处理。
注意1:只要onInterceptTouchEvent()返回false,而且目标控件View::onTouchEvent()返回true,那么事件的每一个动作(按下、移动、抬起等)会都会首先传递到onInterceptTouchEvent()中。

注意2:如果事件传递到某一层的子 view 的 onTouchEvent 上了,这个方法返回了 false ,那么这个事件会从这个 view 往上传递,都是onTouchEvent 来接收。而如果传递到最上面的 onTouchEvent 也返回 false 的话,这个事件就会“消失”,而且接收不到下一次事件。(一次事件指的是 down 到 up 之间的一系列事件)

总结一下就是:onInterceptTouchEvent可以接受到所有的Touch事件,而onTouchEvent则不一定,总体来看, onInterceptTouchEvent是自rootview向下传递, onTouchEvent正好相反。


备注:关于onClick、onLongClick及onTouchEvent时序上处理过程分析:
在一个View中同时覆写了onClick、onLongClick及onTouchEvent的话,onTouchEvent是最先捕捉到ACTION_DOWN和ACTION_UP事件的,其次才可能触发onClick或者onLongClick。
1,onTouch返回false
首先是onTouch事件的down事件发生(返回false),此时,如果长按,触发onLongClick事件;然后是onTouch事件的up事件发生,up完毕,最后触发onClick事件。

2,onTouch返回true
首先是onTouch事件的down事件发生,然后是onTouch事件的up事件发生;期间不触发onClick和onLongClick事件

3,onTouch:down返回true,up返回false:结果同二。

详细分析:
onTouch事件中:down事件返回值标记此次事件是否为点击事件(返回false,是点击事件;返回true,不记为点击事件(为该事件已经被处理)),而up事件标记此次事件结束时间,也就是判断是否为长按。只要当down返回true时候,系统将不把本次事件记录为点击事件,也就不会触发onClick或者onLongClick事件了。因此尽管当up的时候返回false,系统也不会继续触发onClick事件了。

4,onTouch:down返回false,up返回true:
首先是onTouch事件的down事件发生,此时:
长按,触发onLongClick事件,然后是onTouch事件的up事件发生,完毕。
短按,先触发onTouch的up事件,到一定时间后,自动触发onLongClick事件。
机制分析:
onTouch事件中:down事件返回值标记此次事件是否为点击事件(返回false,是点击事件;返回true,不记为点击事件),而up事件标记此次事件结束时间,也就是判断是否为长按。
当down返回false,标记此次事件为点击事件,而up返回了true,则表示此次事件一直没有结束,也就是一直长按下去了,达到长按临界时间后,自然触发长按事件,而onClick事件没有触发到。

总结:
onLongClick发生只有在down为false,up为任意时发生;
Onclick发生在down为false,up为false时发生,
七、关于launcher中
Activity 、View 、Window 、 ViewRoot 、DecorRoot介绍及几者之间的关系:
相关类图


(1)activity: 是逻辑上的东西,增加了生命周期管理等. 里面具体的东西也是view。而且启动activity的实现也是往window里加view,包含一个Window,该Window在Activity的attach方法中通过调用PolicyManager.makeNewWindow创建。

(2)View:最基本的UI组件,表示屏幕上的一个矩形区域,通过 setContentView这个接口进Window显示。1、所有高级UI组件都继承View类而实现的2、一个View在屏幕上占据一块矩形区域3、负责渲染4、负责处理发生的事件5、设置是否可见6、设置是否可以获得焦点等

(3). ViewGroup1、ViewGroup 是View的子类2、View的容器 3、负责对添加进ViewGroup的View进行布局 4、一个ViewGroup可以加入到另一个ViewGroup5、各种layout继承自ViewGroup。ViewGroup与View关系图如下


(4). widget 1、界面中展示的各个小组件2、有独立的事件处理能力3、所有Wiget组件都是继承View而来,继承自View或ViewGroup。
(5)Window:该类提供了一组通用的窗口(Window)操作API,这里的窗口仅仅是程序层面上的,WmS所管理的窗口并不是Window类,而是一个View或者ViewGroup类,一般就是指DecorView类,即一个DecorView就是WmS所管理的一个窗口。Window是一个abstract类型。

(6)PhoneWindow:是Android中的最基本的窗口系统,每个Activity均会创建一个PhoneWindow对象,是Activity和整个View系统交互的接口。

(7)DecorView:DecorView是当前Activity所有View的祖先,该类是一个FrameLayout的子类,并且是PhoneWindow中的一个内部类。DecorView就是对普通的FrameLayout进行了一定的修饰,比如添加一个通用的Titlebar,并响应特定的按键消息等。
Decor View结构图:

1、DecorView为整个Window界面的最顶层View。
2、DecorView只有一个子元素为LinearLayout。代表整个Window界面,包含通知栏,标题栏,内容显示栏三块区域。
3、LinearLayout里有两个FrameLayout子元素。
(20)为标题栏显示界面。只有一个TextView显示应用的名称。也可以自定义标题栏,载入后的自定义标题栏View将加入FrameLayout中。
(21)为内容栏显示界面。就是setContentView()方法载入的布局界面,加入其中。
4、派发从ViewRoot分发来的key、touch、trackball等外部事件;
5、作为PhoneWindow与ViewRoot之间的桥梁,ViewRoot通过DecorView设置窗口属性。

(9) ViewRoot:
1. ViewRoot负责协调decorview与windowmanager直接绘图、事件处理;
2. 向DecorView分发收到的用户发起的event事件,如按键,触屏,轨迹球等事件;
3. 与WindowManagerService交互,完成整个Activity的GUI的绘制。

注意: ViewRoot只是DecorView的代理来接收WindowManagerService发过来的消息,DecorView才是activity Window的展示内容的平台。(ViewRoot实际是一个Handler,ViewRoot建立主View与WindowsManger通讯的桥梁)。
八、View中常用方法简介
onFinishInflate()
当View和它的所有子对象从XML中导入之后,调用此方法
onMeasure(int, int)
View会调用此方法,来确认自己及所有子对象的大小
onLayout(boolean, int, int, int, int,int, int)
当View要为所有子对象分配大小和位置时,调用此方法
onSizeChanged(int, int, int, int)
当View大小改变时,调用此方法
onDraw(Canvas)
当View要绘制它的内容时,调用此方法 (ViewGroup则不需要实现该函数,因为作为容器是“没有内容“的,其包含了多个子view,而子View已经实现了自己的绘制方法)
dispatchDraw()
绘制子视图调用(在view中这是个空函数,具体的视图不需要实现该方法,它是专门为容器类准备的,也就是容器类必须实现该方法)
onKeyDown(int,KeyEvent)
当一个新的按键事件发生时,调用此方法
onKeyUp(int, KeyEvent)
当一个按键释放事件发生时,调用此方法
onMotionEvent(MotionEvent)
当一个动作事件(如触摸)发生时,调用此方法
onFocusChanged(boolean, int)
当View获得或失去焦点时,调用此方法
onAttachedToWindow()
当View附加到一个窗体上时,调用此方法
onDetachedFromWindow()
当View离开它的窗体时,调用此方法
onWindowVisibilityChanged(int)
当窗口中包含的可见的view发生变化时触发
computeScroll()
主要功能是计算拖动的位移量、更新背景、设置要显示的屏幕。


九、常用知识点
1、Ctrl+shift+R 可以查找该工程中的文件(知道文件名但不知道路径时可以使用)。
2、Ctrl+O 显示该类中的所有方法。
3、Alt+?返回
3、./mk sp6820gb u adrpac system当修改某一个system目录下的文件,可以使用此命令打包成一个system.img文件。
4、在ubuntu下面一工程下查找某一个字符串可以使用
Find –name ‘xxx.xxx’ | xargs grep‘xxx’ |grep –v “\.svn/*”
查找xxx.xxx文件中的xxx字符串,不显示带.svn的文件
4、关于抓log方法 –> 在cmd中使用adblogcat –vtime 就会显示log
【Launcher介绍总结】

    推荐阅读