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 

總佈局文件豎屏,主要顯示workspace  HandleView等按鍵

/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監聽內部類

    private final ContentObserver mFavoritesObserver =new ContentObserver(new Handler()) {

        @Override

        public void 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>(callbacks);
        }
}

由於Launcher實現了Callback接口。在mModel中,將傳入的Launcher對象向下轉型爲Callback賦值給mCallbacks變量。並在LauncherModel中獲得了一個Callbacks的軟引用。通過這一過程,Launcher對象作爲CallbackmModel進行綁定,當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<ApplicationInfo>對象中,然後通過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中,從上到下的主要的節點有,DragLayerWorkspace

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) {

                   ……

       return mTouchState != TOUCH_STATE_REST;

}

只有進入了滑動狀態,才進行攔截,進入onTouchEvent執行滑動操作。當mTouchState != TOUCH_STATE_REST  時,就說明沒有進入滑動狀態。(因爲return  true)。

當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). ViewGroup  1、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實際是一個HandlerViewRoot建立主ViewWindowsManger通訊的橋樑)。

八、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中使用adb  logcat –v  time 就會顯示log

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章