Java学习者论坛

 找回密码
 立即注册

QQ登录

只需一步,快速开始

手机号码,快捷登录

恭喜Java学习者论坛(https://www.javaxxz.com)已经为数万Java学习者服务超过8年了!积累会员资料超过10000G+
成为本站VIP会员,下载本站10000G+会员资源,购买链接:点击进入购买VIP会员
JAVA高级面试进阶视频教程Java架构师系统进阶VIP课程

分布式高可用全栈开发微服务教程

Go语言视频零基础入门到精通

Java架构师3期(课件+源码)

Java开发全终端实战租房项目视频教程

SpringBoot2.X入门到高级使用教程

大数据培训第六期全套视频教程

深度学习(CNN RNN GAN)算法原理

Java亿级流量电商系统视频教程

互联网架构师视频教程

年薪50万Spark2.0从入门到精通

年薪50万!人工智能学习路线教程

年薪50万!大数据从入门到精通学习路线年薪50万!机器学习入门到精通视频教程
仿小米商城类app和小程序视频教程深度学习数据分析基础到实战最新黑马javaEE2.1就业课程从 0到JVM实战高手教程 MySQL入门到精通教程
查看: 410|回复: 0

[实例教程]ANDROID系统原理与源码分析

[复制链接]

该用户从未签到

发表于 2011-10-22 12:38:47 | 显示全部楼层 |阅读模式
导读: 众所周知,AlertDialog类对于显示对话。关于AlertDialog的基本用法在这里就不详细介绍了,网上有很多,读者可以自己搜索。那么本文要介绍的是如何随心所欲地控制AlertDialog。
关键字
Android系统原理源码分析
  众所周知,AlertDialog类对于显示对话。关于AlertDialog的基本用法在这里就不详细介绍了,网上有很多,读者可以自己搜索。那么本文要介绍的是如何随心所欲地控制AlertDialog。
  现在我们来看看第一个需求:如果某个应用需要弹出一个对话框。当单击“确定“按钮时完成某些工作,如果这些工作失败,对话框不能关闭。而当成功完成工作后,则关闭对话框。当然,无论何程度情况,单击“取消”按钮都会关闭对话框。
   这个需求并不复杂,也并不过分(虽然我们可以自己弄个Activity来完成这个工作,也可在View上自己放按钮,但这显示有些大炮打蚊子了,如果对 话框上只有一行文本,费这么多劲太不值了)。但使用过AlertDialog的读者都知道,无论单击的哪个按钮,无论按钮单击事件的执行情况如何,对话框 是肯定要关闭的。也就是说,用户无法控制对话框的关闭动作。实际上,关闭对话框的动作已经在Android SDK写死了,并且未给使用者留有任何接口。但我的座右铭是“宇宙中没有什么是不能控制的”。
   既然要控制对放框的关闭行为,首先就得分析是哪些类、哪些代码使这个对话框关闭的。进入AlertDialog类的源代码。在AlertDialog中 只定义了一个变量:mAlert。这个变量是AlertController类型。AlertController类是Android的内部类,在 com.android.internal.app包中,无法通过普通的方式访问。也无法在Eclipse中通过按Ctrl键跟踪进源代码。但可以直接在 Android源代码中找到AlertController.java。我们再回到AlertDialog类中。AlertDialog类实际上只是一个 架子。象设置按钮、设置标题等工作都是由AlertController类完成的。因此,AlertController类才是关键。
  找到AlertController.java文件。打开后不要感到头晕哦,这个文件中的代码是很多地。不过这么多代码对本文的主题也没什么用处。下面就找一下控制按钮的代码。
  在AlertController类的开头就会看到如下的代码:
  View.OnClickListener mButtonHandler = new View.OnClickListener() {
  public void onClick(View v) {
  Message m = null;
  if (v == mButtonPositive && mButtonPositiveMessage != null) {
  m = Message.obtain(mButtonPositiveMessage);
  } else if (v == mButtonNegative && mButtonNegativeMessage != null) {
  m = Message.obtain(mButtonNegativeMessage);
  } else if (v == mButtonNeutral && mButtonNeutralMessage != null) {
  m = Message.obtain(mButtonNeutralMessage);
  }
  if (m != null) {
  m.sendToTarget();
  }
  // Post a message so we dismiss after the above handlers are executed
  mHandler.obtainMessage(ButtonHandler.MSG_DISMISS_DIALOG, mDialogInterface)
  .sendToTarget();
  }
  };
  从这段代码中可以猜出来,前几行代码用来触发对话框中的三个按钮(Positive、Negative和Neutral)的单击事件,而最后的代码则用来关闭对话框(因为我们发现了MSG_DISMISS_DIALOG、猜出来的)。
  mHandler.obtainMessage(ButtonHandler.MSG_DISMISS_DIALOG, mDialogInterface)
  .sendToTarget();
  上面的代码并不是直接来关闭对话框的,而是通过一个Handler来处理,代码如下:
  private static final class ButtonHandler extends Handler {
  // Button clicks have Message.what as the BUTTON{1,2,3} constant
  private static final int MSG_DISMISS_DIALOG = 1;
  private WeakReference《DialogInterface》 mDialog;
  public ButtonHandler(DialogInterface dialog) {
  mDialog = new WeakReference《DialogInterface》(dialog);
  }
  @Override
  public void handleMessage(Message msg) {
  switch (msg.what) {
  case DialogInterface.BUTTON_POSITIVE:
  case DialogInterface.BUTTON_NEGATIVE:
  case DialogInterface.BUTTON_NEUTRAL:
  ((DialogInterface.OnClickListener) msg.obj).onClick(mDialog.get(), msg.what);
  break;
  case MSG_DISMISS_DIALOG:
  ((DialogInterface) msg.obj).dismiss();
  }
  }
  }
  从上面代码的最后可以找到
   ((DialogInterface) msg.obj).dismiss();。现在看了这么多源代码,我们来总结一下对话框按钮单击事件的处理过程。在AlertController处理对 话框按钮时会为每一个按钮添加一个onclick事件。而这个事件类的对象实例就是上面的mButtonHandler。在这个单击事件中首先会通过发送 消息的方式调用为按钮设置的单击事件(也就是通过setPositiveButton等方法的第二个参数设置的单击事件),在触发完按钮的单击事件后,会 通过发送消息的方式调用dismiss方法来关闭对话框。而在AlertController类中定义了一个全局的mHandler变量。在 AlertController类中通过ButtonHandler类来对象来为mHandler赋值。因此,我们只要使用我们自己Handler对象替 换ButtonHandler就可以阻止调用dismiss方法来关闭对话框。下面先在自己的程序中建立一个新的ButtonHandler类(也可叫其 他的名)。
  class ButtonHandler extends Handler
  {
  private WeakReference《DialogInterface》 mDialog;
  public ButtonHandler(DialogInterface dialog)
  {
  mDialog = new WeakReference《DialogInterface》(dialog);
  }
  @Override
  public
  void handleMessage(Message msg)
  {
  switch (msg.what)
  {
  case DialogInterface.BUTTON_POSITIVE:
  case DialogInterface.BUTTON_NEGATIVE:
  case DialogInterface.BUTTON_NEUTRAL:
  ((DialogInterface.OnClickListener) msg.obj).onClick(mDialog
  .get(), msg.what);
  break;
  }
  }
  }
  我们可以看到,上面的类和AlertController中的ButtonHandler类很像,只是支掉了switch语句的最后一个case子句(用于调用dismiss方法)和相关的代码。
下面我们就要为AlertController中的mHandler重新赋值。由于mHandler是private变量,因此,在这里需要使用 Java的反射技术来为mHandler赋值。由于在AlertDialog类中的mAlert变量同样也是private,因此,也需要使用同样的反射 技术来获得mAlert变量。代码如下:
  先建立一个AlertDialog对象
  AlertDialog alertDialog = new AlertDialog.Builder(this)
  .setTitle(“abc”)
  .setMessage(“content”)
  .setIcon(R.drawable.icon)
  .setPositiveButton( “确定”,
  new OnClickListener()
  {
  @Override
  public void onClick(DialogInterface dialog,
  int which)
  {
  }
  }).setNegativeButton(“取消”, new OnClickListener()
  {
  @Override
  public void onClick(DialogInterface dialog, int which)
  {
  dialog.dismiss();
  }
  }).create();
  上面的对话框很普通,单击哪个按钮都会关闭对话框。下面在调用show方法之前来修改一个mHandler变量的值,OK,下面我们就来见证奇迹的时刻。
  try
  {
  Field field = alertDialog1.getClass().getDeclaredField(“mAlert”);
  field.setAccessible(true);
  //
  获得mAlert变量的值
  Object obj = field.get(alertDialog1);
  field = obj.getClass().getDeclaredField(“mHandler”);
  field.setAccessible(true);
  //
  修改mHandler变量的值,使用新的ButtonHandler类
  field.set(obj, new ButtonHandler(alertDialog1));
  }
  catch (Exception e)
  {
  }
  //
  显示对话框
  alertDialog.show();
  我们发现,如果加上try
  catch语句,单击对话框中的确定按钮不会关闭对话框(除非在代码中调用dismiss方法),单击取消按钮则会关闭对话框(因为调用了dismiss方法)。如果去了try…catch代码段,对话框又会恢复正常了。
  虽然上面的代码已经解决了问题,但需要编写的代码仍然比较多,为此,我们也可采用另外一种方法来阻止关闭对话框。这种方法不需要定义任何的类。
   这种方法需要用点技巧。由于系统通过调用dismiss来关闭对话框,那么我们可以在dismiss方法上做点文章。在系统调用dismiss方法时会 首先判断对话框是否已经关闭,如果对话框已经关闭了,就会退出dismiss方法而不再继续关闭对话框了。因此,我们可以欺骗一下系统,当调用 dismiss方法时我们可以让系统以为对话框已经关闭(虽然对话框还没有关闭),这样dismiss方法就失效了,这样即使系统调用了dismiss方 法也无法关闭对话框了。
  下面让我们回到AlertDialog的源代码中,再继续跟踪到AlertDialog的父类Dialog的源 代码中。找到dismissDialog方法。实际上,dismiss方法是通过dismissDialog方法来关闭对话框 的,dismissDialog方法的代码如下:
  private
  void dismissDialog() {
  if (mDecor == null) {
  if (Config.LOGV) Log.v(LOG_TAG,
  “[Dialog] dismiss: already dismissed, ignore”);
  return;
  }
  if (!mShowing) {
  if (Config.LOGV) Log.v(LOG_TAG,
  “[Dialog] dismiss: not showing, ignore”);
  return;
  }
  mWindowManager.removeView(mDecor);
  mDecor = null;
  mWindow.closeAllPanels();
  onStop();
  mShowing = false;
  sendDismiSSMessage();
  }
   该方法后面的代码不用管它,先看if(!mShowing){…}这段代码。这个mShowing变量就是判断对话框是否已关闭的。因此,我们在代码中 通过设置这个变量就可以使系统认为对话框已经关闭,就不再继续关闭对话框了。由于mShowing也是private变量,因此,也需要反射技术来设置这 个变量。我们可以在对话框按钮的单击事件中设置mShowing,代码如下:
  try
  {
  Field field = dialog.getClass()
  .getSuperclass().getDeclaredField(
  “mShowing”);
  field.setAccessible(true);
  //
  将mShowing变量设为false,表示对话框已关闭
  field.set(dialog, false);
  dialog.dismiss();
  }
  catch (Exception e)
  {
  }
   将上面的代码加到哪个按钮的单击事件代码中,哪个按钮就再也无法关闭对话框了。如果要关闭对话框,只需再将mShowing设为true即可。要注意的 是,在一个按钮里设置了mShowing变量,也会影响另一个按钮的关闭对话框功能,因此,需要在每一个按钮的单击事件里都设置mShowing变量的 值。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|手机版|Java学习者论坛 ( 声明:本站资料整理自互联网,用于Java学习者交流学习使用,对资料版权不负任何法律责任,若有侵权请及时联系客服屏蔽删除 )

GMT+8, 2024-6-3 14:04 , Processed in 0.380525 second(s), 46 queries .

Powered by Discuz! X3.4

© 2001-2017 Comsenz Inc.

快速回复 返回顶部 返回列表