Android Window纪要

来源:互联网 发布:网络玄幻小说经典语录 编辑:程序博客网 时间:2024/06/01 08:38

Window概念理解

在Andriod开发中经常提到Activity和View,而位于它们之间的Window却较少涉及。Window所表示的是一个抽象的概念,实际上所有View都是依附于Window之上的,包括Activity中的视图、Dialog中的视图以及Toast中的视图。另外View的事件分发也是由Window传递给View的。

Window的管理

Window是一个抽象类,其具体实现为PhoneWindow,Window通过WindowMaganer来管理,如添加、修改和删除等操作。WindowManager是一个接口,其具体实现类为WindowManagerImpl,有如下几个比较重要的方法:

@Overridepublic void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {    applyDefaultToken(params);    mGlobal.addView(view, params, mDisplay, mParentWindow);}@Overridepublic void updateViewLayout(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {    applyDefaultToken(params);    mGlobal.updateViewLayout(view, params);}@Overridepublic void removeView(View view) {    mGlobal.removeView(view, false);}@Overridepublic void removeViewImmediate(View view) {    mGlobal.removeView(view, true);}

由上述源码可知这几个方法的内部实现是由WindowManagerGlobal实现的。

Window与Activity的关联

通过Activity源码可知,Activity实现了Window.Callback,该接口定义如下:

/** * API from a Window back to its caller.  This allows the client to * intercept key dispatching, panels and menus, etc. */public interface Callback {    /**     * Called to process key events.  At the very least your     * implementation must call     * {@link android.view.Window#superDispatchKeyEvent} to do the     * standard key processing.     *     * @param event The key event.     *     * @return boolean Return true if this event was consumed.     */    public boolean dispatchKeyEvent(KeyEvent event);    /**     * Called to process a key shortcut event.     * At the very least your implementation must call     * {@link android.view.Window#superDispatchKeyShortcutEvent} to do the     * standard key shortcut processing.     *     * @param event The key shortcut event.     * @return True if this event was consumed.     */    public boolean dispatchKeyShortcutEvent(KeyEvent event);    /**     * Called to process touch screen events.  At the very least your     * implementation must call     * {@link android.view.Window#superDispatchTouchEvent} to do the     * standard touch screen processing.     *     * @param event The touch screen event.     *     * @return boolean Return true if this event was consumed.     */    public boolean dispatchTouchEvent(MotionEvent event);    /**     * Called to process trackball events.  At the very least your     * implementation must call     * {@link android.view.Window#superDispatchTrackballEvent} to do the     * standard trackball processing.     *     * @param event The trackball event.     *     * @return boolean Return true if this event was consumed.     */    public boolean dispatchTrackballEvent(MotionEvent event);    /**     * Called to process generic motion events.  At the very least your     * implementation must call     * {@link android.view.Window#superDispatchGenericMotionEvent} to do the     * standard processing.     *     * @param event The generic motion event.     *     * @return boolean Return true if this event was consumed.     */    public boolean dispatchGenericMotionEvent(MotionEvent event);    /**     * Called to process population of {@link AccessibilityEvent}s.     *     * @param event The event.     *     * @return boolean Return true if event population was completed.     */    public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event);    /**     * Instantiate the view to display in the panel for 'featureId'.     * You can return null, in which case the default content (typically     * a menu) will be created for you.     *     * @param featureId Which panel is being created.     *     * @return view The top-level view to place in the panel.     *     * @see #onPreparePanel     */    @Nullable    public View onCreatePanelView(int featureId);    /**     * Initialize the contents of the menu for panel 'featureId'.  This is     * called if onCreatePanelView() returns null, giving you a standard     * menu in which you can place your items.  It is only called once for     * the panel, the first time it is shown.     *     * <p>You can safely hold on to <var>menu</var> (and any items created     * from it), making modifications to it as desired, until the next     * time onCreatePanelMenu() is called for this feature.     *     * @param featureId The panel being created.     * @param menu The menu inside the panel.     *     * @return boolean You must return true for the panel to be displayed;     *         if you return false it will not be shown.     */    public boolean onCreatePanelMenu(int featureId, Menu menu);    /**     * Prepare a panel to be displayed.  This is called right before the     * panel window is shown, every time it is shown.     *     * @param featureId The panel that is being displayed.     * @param view The View that was returned by onCreatePanelView().     * @param menu If onCreatePanelView() returned null, this is the Menu     *             being displayed in the panel.     *     * @return boolean You must return true for the panel to be displayed;     *         if you return false it will not be shown.     *     * @see #onCreatePanelView     */    public boolean onPreparePanel(int featureId, View view, Menu menu);    /**     * Called when a panel's menu is opened by the user. This may also be     * called when the menu is changing from one type to another (for     * example, from the icon menu to the expanded menu).     *     * @param featureId The panel that the menu is in.     * @param menu The menu that is opened.     * @return Return true to allow the menu to open, or false to prevent     *         the menu from opening.     */    public boolean onMenuOpened(int featureId, Menu menu);    /**     * Called when a panel's menu item has been selected by the user.     *     * @param featureId The panel that the menu is in.     * @param item The menu item that was selected.     *     * @return boolean Return true to finish processing of selection, or     *         false to perform the normal menu handling (calling its     *         Runnable or sending a Message to its target Handler).     */    public boolean onMenuItemSelected(int featureId, MenuItem item);    /**     * This is called whenever the current window attributes change.     *     */    public void onWindowAttributesChanged(WindowManager.LayoutParams attrs);    /**     * This hook is called whenever the content view of the screen changes     * (due to a call to     * {@link Window#setContentView(View, android.view.ViewGroup.LayoutParams)     * Window.setContentView} or     * {@link Window#addContentView(View, android.view.ViewGroup.LayoutParams)     * Window.addContentView}).     */    public void onContentChanged();    /**     * This hook is called whenever the window focus changes.  See     * {@link View#onWindowFocusChanged(boolean)     * View.onWindowFocusChanged(boolean)} for more information.     *     * @param hasFocus Whether the window now has focus.     */    public void onWindowFocusChanged(boolean hasFocus);    /**     * Called when the window has been attached to the window manager.     * See {@link View#onAttachedToWindow() View.onAttachedToWindow()}     * for more information.     */    public void onAttachedToWindow();    /**     * Called when the window has been attached to the window manager.     * See {@link View#onDetachedFromWindow() View.onDetachedFromWindow()}     * for more information.     */    public void onDetachedFromWindow();    /**     * Called when a panel is being closed.  If another logical subsequent     * panel is being opened (and this panel is being closed to make room for the subsequent     * panel), this method will NOT be called.     *     * @param featureId The panel that is being displayed.     * @param menu If onCreatePanelView() returned null, this is the Menu     *            being displayed in the panel.     */    public void onPanelClosed(int featureId, Menu menu);    /**     * Called when the user signals the desire to start a search.     *     * @return true if search launched, false if activity refuses (blocks)     *     * @see android.app.Activity#onSearchRequested()     */    public boolean onSearchRequested();    /**     * Called when an action mode is being started for this window. Gives the     * callback an opportunity to handle the action mode in its own unique and     * beautiful way. If this method returns null the system can choose a way     * to present the mode or choose not to start the mode at all.     *     * @param callback Callback to control the lifecycle of this action mode     * @return The ActionMode that was started, or null if the system should present it     */    @Nullable    public ActionMode onWindowStartingActionMode(ActionMode.Callback callback);    /**     * Called when an action mode has been started. The appropriate mode callback     * method will have already been invoked.     *     * @param mode The new mode that has just been started.     */    public void onActionModeStarted(ActionMode mode);    /**     * Called when an action mode has been finished. The appropriate mode callback     * method will have already been invoked.     *     * @param mode The mode that was just finished.     */    public void onActionModeFinished(ActionMode mode);}

其中常见的有如下几个回调:

  • public boolean dispatchTouchEvent(MotionEvent event);
  • public void onWindowFocusChanged(boolean hasFocus);
  • public void onAttachedToWindow();
  • public void onDetachedFromWindow();

由此可见,很多关于Window的回调都是在Activity中处理的,它们的关系非常紧密。

当Activity被创建时,会为该Activity创建一个Window对象,由于Activity实现了Window.Callback,因此对于Window的操作就会在Activity中回调。创建完Window后,就需要把Activity的视图附加到Window上了。这个过程的步骤如下:

1.Activity中的实现

/** * Set the activity content from a layout resource.  The resource will be * inflated, adding all top-level views to the activity. * * @param layoutResID Resource ID to be inflated. * * @see #setContentView(android.view.View) * @see #setContentView(android.view.View, android.view.ViewGroup.LayoutParams) */public void setContentView(int layoutResID) {    getWindow().setContentView(layoutResID);    initWindowDecorActionBar();}

2.Activity把添加视图的任务交给Window来处理,而Window会先创建一个DecorView(是一个FrameLayout),DecorView包含一个ID为android.R.id.content的内容区,其实质也是一个FrameLayout。
3. 在Activity中经常调用的setContentView(int resId),就是把我们的视图添加到DecorView的内容区,也正因为如此,这个添加视图的方法不叫setView,而叫setContentView。添加完成后,Activity的onContentChanged被回调。
4. DecorView添加好视图后,还需要使用WindowMagager的addView方法将其添加到Window中。
5. 以上步骤之后,所添加的视图并不可见,当Activity执行onResume()之后,才会将DecorView设置为可见,这样用户才真正看到了Activity的视图并可以接收用户交互。

0 0
原创粉丝点击