天天看点

Android源码解析之Dialog

出处—http://blog.csdn.net/lilu_leo/article/details/8220020

在学习设计模式建造者模式时,发现AlertDialog和它的内部类Builder就是比较典型的建造者模式,所以先分析下基类Dialog,然后再看子类AlertDialog和它的内部类Builder。

按照惯例,先看下类说明:

[java]  view plain copy

  1. Base class for Dialogs.  
  2. Note: Activities provide a facility to manage the creation, saving and restoring of dialogs. See onCreateDialog(int), onPrepareDialog(int, Dialog), showDialog(int), and dismissDialog(int). If these methods are used, getOwnerActivity() will return the Activity that managed this dialog.  
  3. Often you will want to have a Dialog display on top of the current input method, because there is no reason for it to accept text. You can do this by setting the WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM window flag (assuming your Dialog takes input focus, as it the default) with the following code:  
  4.  getWindow().setFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM,  
  5.          WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);  

Dialog是一系列Dialogs的基类。

注意:Activity提供了onCreateDialog(int)、onPrepareDialog(int, Dialog)和showDialog(int)这一些列方法用于管理dialog的创建、保存和恢复(注:关于onCreateDialog的用法见于:onCreateDialog方法及示例)。如果使用了以上方法,Dialog的getOwnerActivity方法就会返回创建Dialog的Activity。

如果你的Dialog不需要输入文本,想要显示在当前显示的输入法的上面,可以像下面代码通过设置WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM来实现(如果想要获取输入,则不用设置,默认获取焦点)

[java]  view plain copy

  1. getWindow().setFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM,  
  2.         WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);  

使用WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM此标志位表示隐藏输入法。

看一下所用到的全局变量:

[java]  view plain copy

  1. public class Dialog implements DialogInterface, Window.Callback,  
  2.         KeyEvent.Callback, OnCreateContextMenuListener {  
  3.     private static final String TAG = "Dialog";  
  4.     private Activity mOwnerActivity;  
  5.     final Context mContext;  
  6.     final WindowManager mWindowManager;  
  7.     Window mWindow;  
  8.     View mDecor;  
  9.     private ActionBarImpl mActionBar;  
  10.     protected boolean mCancelable = true;  
  11.     private String mCancelAndDismissTaken;  
  12.     private Message mCancelMessage;  
  13.     private Message mDismissMessage;  
  14.     private Message mShowMessage;  
  15.     private OnKeyListener mOnKeyListener;  
  16.     private boolean mCreated = false;  
  17.     private boolean mShowing = false;  
  18.     private boolean mCanceled = false;  
  19.     private final Thread mUiThread;  
  20.     private final Handler mHandler = new Handler();  
  21.     private static final int DISMISS = 0x43;  
  22.     private static final int CANCEL = 0x44;  
  23.     private static final int SHOW = 0x45;  
  24.     private Handler mListenersHandler;  
  25.     private ActionMode mActionMode;  
  26.     private final Runnable mDismissAction = new Runnable() {  
  27.         public void run() {  
  28.             dismissDialog();  
  29.         }  
  30.     };  

变量都比较简单,这里不再详述。

Dialog类实现了DialogInterface, Window.Callback,KeyEvent.Callback, OnCreateContextMenuListener这些接口,今天看下DialogInterface接口,其他接口在Activity源码和Menu源码的时候再看。

[java]  view plain copy

  1. public interface DialogInterface {      
  2.     public static final int BUTTON_POSITIVE = -1;  
  3.     public static final int BUTTON_NEGATIVE = -2;  
  4.     public static final int BUTTON_NEUTRAL = -3;  
  5.     @Deprecated  
  6.     public static final int BUTTON1 = BUTTON_POSITIVE;  
  7.     @Deprecated  
  8.     public static final int BUTTON2 = BUTTON_NEGATIVE;  
  9.     @Deprecated  
  10.     public static final int BUTTON3 = BUTTON_NEUTRAL;  
  11.     public void cancel();  
  12.     public void dismiss();  
  13.     interface OnCancelListener {  
  14.         public void onCancel(DialogInterface dialog);  
  15.     }  
  16.     interface OnDismissListener {  
  17.         public void onDismiss(DialogInterface dialog);  
  18.     }  
  19.     interface OnShowListener {  
  20.         public void onShow(DialogInterface dialog);  
  21.     }  
  22.     interface OnClickListener {  
  23.         public void onClick(DialogInterface dialog, int which);  
  24.     }  
  25.     interface OnMultiChoiceClickListener {  
  26.         public void onClick(DialogInterface dialog, int which, boolean isChecked);  
  27.     }  
  28.     interface OnKeyListener {  
  29.         public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event);  
  30.     }  
  31. }  

里面有代表三个button的变量,还有cancel()、dismiss()、还有OnCancelListener、OnDismissListener、OnShowListener、OnClickListener、OnMultiChoiceClickListener、OnKeyListener这些回调接口,会在AlertDialog源码解析中来说明这些方法。

下面是它的构造方法:

[java]  view plain copy

  1.     public Dialog(Context context) {  
  2.         this(context, 0, true);  
  3.     }  
  4.     public Dialog(Context context, int theme) {  
  5.         this(context, theme, true);  
  6.     }  
  7.     Dialog(Context context, int theme, boolean createContextWrapper) {  
  8.         if (theme == 0) {  
  9.             TypedValue outValue = new TypedValue();  
  10.             context.getTheme().resolveAttribute(com.android.internal.R.attr.dialogTheme,  
  11.                     outValue, true);  
  12.             theme = outValue.resourceId;  
  13.         }  
  14.         mContext = createContextWrapper ? new ContextThemeWrapper(context, theme) : context;  
  15.         mWindowManager = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE);  
  16.         Window w = PolicyManager.makeNewWindow(mContext);  
  17.         mWindow = w;  
  18.         w.setCallback(this);  
  19.         w.setWindowManager(mWindowManager, null, null);  
  20.         w.setGravity(Gravity.CENTER);  
  21.         mUiThread = Thread.currentThread();  
  22.         mListenersHandler = new ListenersHandler(this);  
  23.     }  
  24.     @Deprecated  
  25.     protected Dialog(Context context, boolean cancelable,  
  26.             Message cancelCallback) {  
  27.         this(context);  
  28.         mCancelable = cancelable;  
  29.         mCancelMessage = cancelCallback;  
  30.     }  
  31.     protected Dialog(Context context, boolean cancelable,  
  32.             OnCancelListener cancelListener) {  
  33.         this(context);  
  34.         mCancelable = cancelable;  
  35.         setOnCancelListener(cancelListener);  
  36.     }  

第一个构造方法是使用对话框风格,第二个构造方法使用自定义的对话框风格,这两个构造方法都是调用的下面的Dialog方法,我们注意到他的权限是缺省,就是我我们在外部不能直接使用该构造方法。

[java]  view plain copy

  1. Dialog(Context context, int theme, boolean createContextWrapper) {  
  2.         if (theme == 0) {  
  3.             TypedValue outValue = new TypedValue();  
  4.             context.getTheme().resolveAttribute(com.android.internal.R.attr.dialogTheme,  
  5.                     outValue, true);  
  6.             theme = outValue.resourceId;  
  7.         }  
  8.         mContext = createContextWrapper ? new ContextThemeWrapper(context, theme) : context;  
  9.         mWindowManager = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE);  
  10.         Window w = PolicyManager.makeNewWindow(mContext);  
  11.         mWindow = w;  
  12.         w.setCallback(this);  
  13.         w.setWindowManager(mWindowManager, null, null);  
  14.         w.setGravity(Gravity.CENTER);  
  15.         mUiThread = Thread.currentThread();  
  16.         mListenersHandler = new ListenersHandler(this);  
  17.     }  

如果theme为0,则使用系统定义的风格,然后初始化mWindow。

第三个构造方法被Deprecated掉,不看,第四个可以实现取消回调。

再看下面的两个方法:

[java]  view plain copy

  1.     public final Context getContext() {  
  2.         return mContext;  
  3.     }  
  4.     public ActionBar getActionBar() {  
  5.         return mActionBar;  
  6.     }  

获取Dialog运行的山下文环境和ActionBar。

[java]  view plain copy

  1.     public final void setOwnerActivity(Activity activity) {  
  2.         mOwnerActivity = activity;  
  3.         getWindow().setVolumeControlStream(mOwnerActivity.getVolumeControlStream());  
  4.     }  
  5.     public final Activity getOwnerActivity() {  
  6.         return mOwnerActivity;  
  7.     }  

设置和获取Dialog所属的Activity和获取(如果在onCreate()之外创建dialog,它不会附属于任何的Activity,可以使用dialog的setOwnerActivity(Activity)来设置),调用showDialog方法的Activity默认情况下就是要返回的Activity。

[java]  view plain copy

  1. public boolean isShowing() {  
  2.     return mShowing;  
  3. }  

判断当前Dialog是否显示。

[java]  view plain copy

  1.     public void show() {  
  2.         if (mShowing) {  
  3.             if (mDecor != null) {  
  4.                 if (mWindow.hasFeature(Window.FEATURE_ACTION_BAR)) {  
  5.                     mWindow.invalidatePanelMenu(Window.FEATURE_ACTION_BAR);  
  6.                 }  
  7.                 mDecor.setVisibility(View.VISIBLE);  
  8.             }  
  9.             return;  
  10.         }  
  11.         mCanceled = false;  
  12.         if (!mCreated) {  
  13.             dispatchOnCreate(null);  
  14.         }  
  15.         onStart();  
  16.         mDecor = mWindow.getDecorView();  
  17.         if (mActionBar == null && mWindow.hasFeature(Window.FEATURE_ACTION_BAR)) {  
  18.             mActionBar = new ActionBarImpl(this);  
  19.         }  
  20.         WindowManager.LayoutParams l = mWindow.getAttributes();  
  21.         if ((l.softInputMode  
  22.                 & WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION) == 0) {  
  23.             WindowManager.LayoutParams nl = new WindowManager.LayoutParams();  
  24.             nl.copyFrom(l);  
  25.             nl.softInputMode |=  
  26.                     WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION;  
  27.             l = nl;  
  28.         }  
  29.         try {  
  30.             mWindowManager.addView(mDecor, l);  
  31.             mShowing = true;  
  32.             sendShowMessage();  
  33.         } finally {  
  34.         }  
  35.     }  

显示创建的dialog,它是不透明的并且你不能在它显示的时候重载show方法,可以在onStart方法里实现。当mCreate为false的时候调用了dispatchOnCreate方法同时里面调用onCreate方法确保Dialog被初始化:

[java]  view plain copy

  1. // internal method to make sure mcreated is set properly without requiring  
  2.     // users to call through to super in onCreate  
  3.     void dispatchOnCreate(Bundle savedInstanceState) {  
  4.         if (!mCreated) {  
  5.             onCreate(savedInstanceState);  
  6.             mCreated = true;  
  7.         }  
  8.     }  
  9.     protected void onCreate(Bundle savedInstanceState) {  
  10.     }  

[java]  view plain copy

  1.     protected void onStart() {  
  2.         if (mActionBar != null) mActionBar.setShowHideAnimationEnabled(true);  
  3.     }  

一切都创建好以后:调用sendShowMessage方法向UI线程发送一个消息:

[java]  view plain copy

  1. private void sendShowMessage() {  
  2.         if (mShowMessage != null) {  
  3.             // Obtain a new message so this dialog can be re-used  
  4.             Message.obtain(mShowMessage).sendToTarget();  
  5.         }  
  6.     }  

隐藏Dialog(但不是去除Dialog):

[java]  view plain copy

  1.     public void hide() {  
  2.         if (mDecor != null) {  
  3.             mDecor.setVisibility(View.GONE);  
  4.         }  
  5.     }  

去除Dialog:

[java]  view plain copy

  1. public void dismiss() {  
  2.     if (Thread.currentThread() != mUiThread) {  
  3.         mHandler.post(mDismissAction);  
  4.     } else {  
  5.         mHandler.removeCallbacks(mDismissAction);  
  6.         mDismissAction.run();  
  7.     }  
  8. }  

从屏幕上去除dialog,这个方法在任何线程中都是安全的,注意当dialog被取消,不要重写这个方法。可以在onStop方法里面调用dismiss方法。

里面执行了mDismissAction这个runnable:

[java]  view plain copy

  1. private final Runnable mDismissAction = new Runnable() {  
  2.         public void run() {  
  3.             dismissDialog();  
  4.         }  
  5.     };  

 主要执行dismissDialog方法:

[java]  view plain copy

  1. void dismissDialog() {  
  2.        if (mDecor == null || !mShowing) {  
  3.            return;  
  4.        }  
  5.        if (mWindow.isDestroyed()) {  
  6.            Log.e(TAG, "Tried to dismissDialog() but the Dialog's window was already destroyed!");  
  7.            return;  
  8.        }  
  9.        try {  
  10.            mWindowManager.removeView(mDecor);  
  11.        } finally {  
  12.            if (mActionMode != null) {  
  13.                mActionMode.finish();  
  14.            }  
  15.            mDecor = null;  
  16.            mWindow.closeAllPanels();  
  17.            onStop();  
  18.            mShowing = false;  
  19.            sendDismissMessage();  
  20.        }  
  21.    }  

里面主要任务就是销毁一切资源,然后里面调用了onStop方法:

[java]  view plain copy

  1. protected void onStop() {  
  2.     if (mActionBar != null) mActionBar.setShowHideAnimationEnabled(false);  
  3. }  

把ActionBar功能设为false。上面还调用了senDismissMessage方法:

[java]  view plain copy

  1. private void sendDismissMessage() {  
  2.         if (mDismissMessage != null) {  
  3.             // Obtain a new message so this dialog can be re-used  
  4.             Message.obtain(mDismissMessage).sendToTarget();  
  5.         }  
  6.     }  

下一个就是保持状态的onSaveInstanceState和从保存状态中恢复onRestoreInstanceState:

[java]  view plain copy

  1. public Bundle onSaveInstanceState() {  
  2.     Bundle bundle = new Bundle();  
  3.     bundle.putBoolean(DIALOG_SHOWING_TAG, mShowing);  
  4.     if (mCreated) {  
  5.         bundle.putBundle(DIALOG_HIERARCHY_TAG, mWindow.saveHierarchyState());  
  6.     }  
  7.     return bundle;  
  8. }  
  9. public void onRestoreInstanceState(Bundle savedInstanceState) {  
  10.     final Bundle dialogHierarchyState = savedInstanceState.getBundle(DIALOG_HIERARCHY_TAG);  
  11.     if (dialogHierarchyState == null) {  
  12.         // dialog has never been shown, or onCreated, nothing to restore.  
  13.         return;  
  14.     }  
  15.     dispatchOnCreate(savedInstanceState);  
  16.     mWindow.restoreHierarchyState(dialogHierarchyState);  
  17.     if (savedInstanceState.getBoolean(DIALOG_SHOWING_TAG)) {  
  18.         show();  
  19.     }  
  20. }  

下一个方法是获取当前的Window用于直接访问其API而不是通过Activity或者Screen:

[java]  view plain copy

  1. public Window getWindow() {  
  2.     return mWindow;  
  3. }  

再获取当前拥有焦点的View:

[java]  view plain copy

  1.  public View getCurrentFocus() {  
  2.      return mWindow != null ? mWindow.getCurrentFocus() : null;  
  3.  }  

还可以在onStart方法里面调用findViewById来通过ID获取xml文件中的View:

[java]  view plain copy

  1.     public View findViewById(int id) {  
  2.         return mWindow.findViewById(id);  
  3.     }  

也可以通过ID和View设置Dialog的View:

[java]  view plain copy

  1. public void setContentView(int layoutResID) {  
  2.     mWindow.setContentView(layoutResID);  
  3. }  
  4. public void setContentView(View view) {  
  5.     mWindow.setContentView(view);  
  6. }  

还可以添加View的属性:

[java]  view plain copy

  1.     public void setContentView(View view, ViewGroup.LayoutParams params) {  
  2.         mWindow.setContentView(view, params);  
  3.     }  

在Dialog已存在的View的基础上,再添加一个View:

[java]  view plain copy

  1.  public void addContentView(View view, ViewGroup.LayoutParams params) {  
  2.      mWindow.addContentView(view, params);  
  3.  }  

先前的View并不会被去除。

为Dialog设置标题:

[java]  view plain copy

  1. public void setTitle(CharSequence title) {  
  2.     mWindow.setTitle(title);  
  3.     mWindow.getAttributes().setTitle(title);  
  4. }  
  5. public void setTitle(int titleId) {  
  6.     setTitle(mContext.getText(titleId));  
  7. }  

onKeyDown只处理了back键:

[java]  view plain copy

  1.     public boolean onKeyDown(int keyCode, KeyEvent event) {  
  2.         if (keyCode == KeyEvent.KEYCODE_BACK) {  
  3.             event.startTracking();  
  4.             return true;  
  5.         }  
  6.         return false;  

长按则不做任何处理:

[java]  view plain copy

  1. public boolean onKeyLongPress(int keyCode, KeyEvent event) {  
  2.     return false;  
  3. }  

按键松开:

[java]  view plain copy

  1. public boolean onKeyUp(int keyCode, KeyEvent event) {  
  2.     if (keyCode == KeyEvent.KEYCODE_BACK && event.isTracking()  
  3.             && !event.isCanceled()) {  
  4.         onBackPressed();  
  5.         return true;  
  6.     }  
  7.     return false;  
  8. }  

还是只处理back键,调用onBackPressed:

[java]  view plain copy

  1. public void onBackPressed() {  
  2.     if (mCancelable) {  
  3.         cancel();  
  4.     }  
  5. }  

这个方法默认实现当你按返回键的时候简单的取消dialog,如果你想实现其他功能,可以重写它。

[java]  view plain copy

  1.     public boolean onKeyShortcut(int keyCode, KeyEvent event) {  
  2.         return false;  

对多次重复按键不做任何响应:

[java]  view plain copy

  1.  public boolean onKeyMultiple(int keyCode, int repeatCount, KeyEvent event) {  
  2.      return false;  
  3.  }  

对于快捷键,不做任何处理。

[java]  view plain copy

  1.     public boolean onTouchEvent(MotionEvent event) {  
  2.         if (mCancelable && mShowing && mWindow.shouldCloseOnTouch(mContext, event)) {  
  3.             cancel();  
  4.             return true;  
  5.         }  
  6.         return false;  
  7.     }  

onTouch事件,当发生在dialog区域内,不做任何事,发生在区域外,去除Dialog。

[java]  view plain copy

  1.     public void cancel() {  
  2.         if (!mCanceled && mCancelMessage != null) {  
  3.             mCanceled = true;  
  4.             // Obtain a new message so this dialog can be re-used  
  5.             Message.obtain(mCancelMessage).sendToTarget();  
  6.         }  
  7.         dismiss();  
  8.     }  

取消dialog。

好吧,下面还有轨迹球:

[java]  view plain copy

  1.  public boolean onTrackballEvent(MotionEvent event) {  
  2.      return false;  
  3.  }  

实现该方法来处理触屏事件. 一般的动作事件,描述操纵杆移动、鼠标悬停、触控板事件、滚轮移动以及其他输入事件. 动作 源指定了接收到事件的类型.实现该方法必须 必须在处理事件之前检测动作源的标志位.下面是如果处理的示例代码. 发生源为 SOURCE_CLASS_POINTER 的动作事件发送到光标下的视图. 所有其他发生源的动作时间发送到拥有焦点的视图.这里还是不做任何处理。(众所周知,现在轨迹球已经基本消失)

当Window的属性发生改变时,会重新设置属性:

[java]  view plain copy

  1. public void onWindowAttributesChanged(WindowManager.LayoutParams params) {  
  2.         if (mDecor != null) {  
  3.             mWindowManager.updateViewLayout(mDecor, params);  
  4.         }  
  5.     }  

当内容、焦点、Window添加或移除View都没有处理。

[java]  view plain copy

  1. public void onContentChanged() {  
  2.    }  
  3.    public void onWindowFocusChanged(boolean hasFocus) {  
  4.    }  
  5.    public void onAttachedToWindow() {  
  6.    }  
  7.    public void onDetachedFromWindow() {  
  8.    }  

下面几个方法就是把一系列点击、触屏、滑动轨迹球等事件往上分发传递否则就调用本类中方法处理,你也可以在重写这些方法使它在向上分发传递事件之前做一些自己的事。

[java]  view plain copy

  1. public boolean dispatchKeyEvent(KeyEvent event) {  
  2.     if ((mOnKeyListener != null) && (mOnKeyListener.onKey(this, event.getKeyCode(), event))) {  
  3.         return true;  
  4.     }  
  5.     if (mWindow.superDispatchKeyEvent(event)) {  
  6.         return true;  
  7.     }  
  8.     return event.dispatch(this, mDecor != null  
  9.             ? mDecor.getKeyDispatcherState() : null, this);  
  10. }  
  11. public boolean dispatchKeyShortcutEvent(KeyEvent event) {  
  12.     if (mWindow.superDispatchKeyShortcutEvent(event)) {  
  13.         return true;  
  14.     }  
  15.     return onKeyShortcut(event.getKeyCode(), event);  
  16. }  
  17. public boolean dispatchTouchEvent(MotionEvent ev) {  
  18.     if (mWindow.superDispatchTouchEvent(ev)) {  
  19.         return true;  
  20.     }  
  21.     return onTouchEvent(ev);  
  22. }  
  23. public boolean dispatchTrackballEvent(MotionEvent ev) {  
  24.     if (mWindow.superDispatchTrackballEvent(ev)) {  
  25.         return true;  
  26.     }  
  27.     return onTrackballEvent(ev);  
  28. }  
  29. public boolean dispatchGenericMotionEvent(MotionEvent ev) {  
  30.     if (mWindow.superDispatchGenericMotionEvent(ev)) {  
  31.         return true;  
  32.     }  
  33.     return onGenericMotionEvent(ev);  
  34. }  

分发传递dispatchPopulateAccessibilityEvent:

[java]  view plain copy

  1. public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {  
  2.         event.setClassName(getClass().getName());  
  3.         event.setPackageName(mContext.getPackageName());  
  4.         LayoutParams params = getWindow().getAttributes();  
  5.         boolean isFullScreen = (params.width == LayoutParams.MATCH_PARENT) &&  
  6.             (params.height == LayoutParams.MATCH_PARENT);  
  7.         event.setFullScreen(isFullScreen);  
  8.         return false;  
  9.     }  

[java]  view plain copy

  1.     public View onCreatePanelView(int featureId) {  
  2.         return null;  
  3.     }  

实现Window.Callback接口的onCreatePanelView方法,简单的实现就是返回null。

[java]  view plain copy

  1.     public boolean onCreatePanelMenu(int featureId, Menu menu) {  
  2.         if (featureId == Window.FEATURE_OPTIONS_PANEL) {  
  3.             return onCreateOptionsMenu(menu);  
  4.         }  
  5.         return false;  
  6.     }  

创建一个菜单,实现Window.Callback接口的onCreatePanelMenu方法。

[java]  view plain copy

  1. public boolean onPreparePanel(int featureId, View view, Menu menu) {  
  2.     if (featureId == Window.FEATURE_OPTIONS_PANEL && menu != null) {  
  3.         boolean goforit = onPrepareOptionsMenu(menu);  
  4.         return goforit && menu.hasVisibleItems();  
  5.     }  
  6.     return true;  
  7. }  

实现Window.Callback接口的onPreparePanel方法。每次当panel窗口显示前,都会调用该函数,返回true显示,false则不显示。

[java]  view plain copy

  1. public boolean onMenuOpened(int featureId, Menu menu) {  
  2.     if (featureId == Window.FEATURE_ACTION_BAR) {  
  3.         mActionBar.dispatchMenuVisibilityChanged(true);  
  4.     }  
  5.     return true;  
  6. }  

实现Window.Callback接口的onMenuOpened方法。当菜单打开时,调用该方法。

[java]  view plain copy

  1. public boolean onMenuItemSelected(int featureId, MenuItem item) {  
  2.     return false;  
  3. }  

实现 Window.Callback接口的onMenuItemSelected方法。 不做任何处理。

[java]  view plain copy

  1. public void onPanelClosed(int featureId, Menu menu) {  
  2.     if (featureId == Window.FEATURE_ACTION_BAR) {  
  3.         mActionBar.dispatchMenuVisibilityChanged(false);  
  4.     }  
  5. }  

实现Window.Callback接口的onPanelClosed方法。当featureId为Window.FEATURE_ACTION_BAR时,修改ActionBar的分发事件。

[java]  view plain copy

  1. public boolean onCreateOptionsMenu(Menu menu) {  
  2.     return true;  
  3. }  

调用 创建该Dialog的Activity的onCreateOptionMenu方法。

[java]  view plain copy

  1.     public boolean onPrepareOptionsMenu(Menu menu) {  
  2.         return true;  
  3.     }  

调用创建Activity的onCreatePrepareOptionsMenu方法。

[java]  view plain copy

  1. public boolean onOptionsItemSelected(MenuItem item) {  
  2.     return false;  
  3. }  
  4. public void onOptionsMenuClosed(Menu menu) {  
  5. }  

对选项菜单的操作,两个都未做处理。

[java]  view plain copy

  1. public void openOptionsMenu() {  
  2.     mWindow.openPanel(Window.FEATURE_OPTIONS_PANEL, null);  
  3. }  
  4. public void closeOptionsMenu() {  
  5.     mWindow.closePanel(Window.FEATURE_OPTIONS_PANEL);  
  6. }  
  7. public void invalidateOptionsMenu() {  
  8.     mWindow.invalidatePanelMenu(Window.FEATURE_OPTIONS_PANEL);  
  9. }  

对选项菜单的三个操作,均是调用的Window类里面的方法。

[java]  view plain copy

  1.     public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {  
  2.     }  

创建上下文菜单,未处理。

为一个View注册和取消注册一个上下文菜单:

[java]  view plain copy

  1. public void registerForContextMenu(View view) {  
  2.     view.setOnCreateContextMenuListener(this);  
  3. }  
  4. public void unregisterForContextMenu(View view) {  
  5.     view.setOnCreateContextMenuListener(null);  
  6. }  

打开一个View的上下文菜单:

[java]  view plain copy

  1.  public void openContextMenu(View view) {  
  2.      view.showContextMenu();  
  3.  }  

[java]  view plain copy

  1. public boolean onContextItemSelected(MenuItem item) {  
  2.     return false;  
  3. }  

上下文菜单选项被处理,未做任何事情。

[java]  view plain copy

  1. public void onContextMenuClosed(Menu menu) {  
  2. }  

上下文菜单关闭。

[java]  view plain copy

  1.     public boolean onSearchRequested() {  
  2.         final SearchManager searchManager = (SearchManager) mContext  
  3.                 .getSystemService(Context.SEARCH_SERVICE);  
  4.         // associate search with owner activity  
  5.         final ComponentName appName = getAssociatedActivity();  
  6.         if (appName != null && searchManager.getSearchableInfo(appName) != null) {  
  7.             searchManager.startSearch(null, false, appName, null, false);  
  8.             dismiss();  
  9.             return true;  
  10.         } else {  
  11.             return false;  
  12.         }  
  13.     }  

这个钩子方法会在用户想要搜索的时候被调用。

[java]  view plain copy

  1. public ActionMode onWindowStartingActionMode(ActionMode.Callback callback) {  
  2.        if (mActionBar != null) {  
  3.            return mActionBar.startActionMode(callback);  
  4.        }  
  5.        return null;  
  6.    }  

通过系统给Activity一个控制UI操作模式(Give the Activity a chance to control the UI for an action mode requested by the system.)

[java]  view plain copy

  1.     public void onActionModeStarted(ActionMode mode) {  
  2.         mActionMode = mode;  
  3.     }  
  4.     public void onActionModeFinished(ActionMode mode) {  
  5.         if (mode == mActionMode) {  
  6.             mActionMode = null;  
  7.         }  
  8.     }  

注意,如果你重写这个方法,你一定要调用父类的super.onActionModeFinished(mode)。开始时候设置mode,结束时把mode设为空。

[java]  view plain copy

  1.    private ComponentName getAssociatedActivity() {  
  2.        Activity activity = mOwnerActivity;  
  3.        Context context = getContext();  
  4.        while (activity == null && context != null) {  
  5.            if (context instanceof Activity) {  
  6.                activity = (Activity) context;  // found it!  
  7.            } else {  
  8.                context = (context instanceof ContextWrapper) ?  
  9.                        ((ContextWrapper) context).getBaseContext() : // unwrap one level  
  10.                        null;                                         // done  
  11.            }  
  12.        }  
  13.        return activity == null ? null : activity.getComponentName();  
  14.    }  

返回相关联activity的名字。

[java]  view plain copy

  1.     public void takeKeyEvents(boolean get) {  
  2.         mWindow.takeKeyEvents(get);  
  3.     }  

请求来自Dialog的的按键事件,如果dialog上面没有view获取焦点,而且这个dialog想要处理按键事件,就调用该方法。

[java]  view plain copy

  1.  public final boolean requestWindowFeature(int featureId) {  
  2.      return getWindow().requestFeature(featureId);  
  3.  }  

设置window的属性。

[java]  view plain copy

  1.     public final void setFeatureDrawableResource(int featureId, int resId) {  
  2.         getWindow().setFeatureDrawableResource(featureId, resId);  
  3.     }  
  4.     public final void setFeatureDrawableUri(int featureId, Uri uri) {  
  5.         getWindow().setFeatureDrawableUri(featureId, uri);  
  6.     }  
  7.     public final void setFeatureDrawable(int featureId, Drawable drawable) {  
  8.         getWindow().setFeatureDrawable(featureId, drawable);  
  9.     }  
  10.     public final void setFeatureDrawableAlpha(int featureId, int alpha) {  
  11.         getWindow().setFeatureDrawableAlpha(featureId, alpha);  
  12.     }  

设置一系列的drawable特性。

[java]  view plain copy

  1.  public void setCancelable(boolean flag) {  
  2.      mCancelable = flag;  
  3.  }  

设置dialog是否可以取消。

[java]  view plain copy

  1. public void setCanceledOnTouchOutside(boolean cancel) {  
  2.     if (cancel && !mCancelable) {  
  3.         mCancelable = true;  
  4.     }  
  5.     mWindow.setCloseOnTouchOutside(cancel);  
  6. }  

设置当触摸dialog外部时,dialog是否可以取消。

[java]  view plain copy

  1.    public void setOnCancelListener(final OnCancelListener listener) {  
  2.        if (mCancelAndDismissTaken != null) {  
  3.            throw new IllegalStateException(  
  4.                    "OnCancelListener is already taken by "  
  5.                    + mCancelAndDismissTaken + " and can not be replaced.");  
  6.        }  
  7.        if (listener != null) {  
  8.            mCancelMessage = mListenersHandler.obtainMessage(CANCEL, listener);  
  9.        } else {  
  10.            mCancelMessage = null;  
  11.        }  
  12.    }  

设置一个当dialog被取消时,会被调用的监听。

[java]  view plain copy

  1.     public void setCancelMessage(final Message msg) {  
  2.         mCancelMessage = msg;  
  3.     }  

当dialog被取消时,设置发送的信息。

[java]  view plain copy

  1. public void setOnDismissListener(final OnDismissListener listener) {  
  2.     if (mCancelAndDismissTaken != null) {  
  3.         throw new IllegalStateException(  
  4.                 "OnDismissListener is already taken by "  
  5.                 + mCancelAndDismissTaken + " and can not be replaced.");  
  6.     }  
  7.     if (listener != null) {  
  8.         mDismissMessage = mListenersHandler.obtainMessage(DISMISS, listener);  
  9.     } else {  
  10.         mDismissMessage = null;  
  11.     }  
  12. }  

设置一个当dialog被销毁时,会被调用的监听。

[java]  view plain copy

  1.  public void setOnShowListener(OnShowListener listener) {  
  2.      if (listener != null) {  
  3.          mShowMessage = mListenersHandler.obtainMessage(SHOW, listener);  
  4.      } else {  
  5.          mShowMessage = null;  
  6.      }  
  7.  }  

设置一个当dialog显示时, 会被调用的监听 。

[java]  view plain copy

  1. public void setDismissMessage(final Message msg) {  
  2.     mDismissMessage = msg;  
  3. }  

设置dialog被销毁时,发送的信息。

[java]  view plain copy

  1.     public boolean takeCancelAndDismissListeners(String msg, final OnCancelListener cancel,  
  2.             final OnDismissListener dismiss) {  
  3.         if (mCancelAndDismissTaken != null) {  
  4.             mCancelAndDismissTaken = null;  
  5.         } else if (mCancelMessage != null || mDismissMessage != null) {  
  6.             return false;  
  7.         }  
  8.         setOnCancelListener(cancel);  
  9.         setOnDismissListener(dismiss);  
  10.         mCancelAndDismissTaken = msg;  
  11.         return true;  
  12.     }  

同时设置OnCancelListener和OnDismissListener。

[java]  view plain copy

  1. public final void setVolumeControlStream(int streamType) {  
  2.     getWindow().setVolumeControlStream(streamType);  
  3. }  
  4. public final int getVolumeControlStream() {  
  5.     return getWindow().getVolumeControlStream();  
  6. }  

设置和获取Dialog所属的Activity中音量控制键控制的音频流。

[java]  view plain copy

  1. public void setOnKeyListener(final OnKeyListener onKeyListener) {  
  2.     mOnKeyListener = onKeyListener;  
  3. }  

设置一个回调,当按键事件被分发到dialog 回调函数会被调用。

[java]  view plain copy

  1. private static final class ListenersHandler extends Handler {  
  2.         private WeakReference<DialogInterface> mDialog;  
  3.         public ListenersHandler(Dialog dialog) {  
  4.             mDialog = new WeakReference<DialogInterface>(dialog);  
  5.         }  
  6.         @Override  
  7.         public void handleMessage(Message msg) {  
  8.             switch (msg.what) {  
  9.                 case DISMISS:  
  10.                     ((OnDismissListener) msg.obj).onDismiss(mDialog.get());  
  11.                     break;  
  12.                 case CANCEL:  
  13.                     ((OnCancelListener) msg.obj).onCancel(mDialog.get());  
  14.                     break;  
  15.                 case SHOW:  
  16.                     ((OnShowListener) msg.obj).onShow(mDialog.get());  
  17.                     break;  
  18.             }  
  19.         }  
  20.     }  

ListenersHandler的定义。