专栏首页编程思想之路Android6.0源码分析之menu键弹出popupwindow菜单流程分析

Android6.0源码分析之menu键弹出popupwindow菜单流程分析

例如上图,在按下菜单键后会弹出对应的菜单选项,准确来说,是在菜单键弹起后出现的一个popupwindow,那么从菜单键弹起到popupwindow创建所涉及到的历程是怎样的呢?

理论上是底层监测menu按键键值,通知framework层,framework经过一系列的处理后分发给上层,或者拦截掉

现在是假设framework层已经把menu按键分发给了用户,那么接下里就是activity进行响应,所以从Activity开始看起,整体流程如下:

从按键弹起framework层分发到activity开始,到弹出popupwindow结束整个流程图

代码所在目录如下

流程图中所涉及到的一些只是单纯的作为中介调用了一下,按着流程自己也可以看到,现在是挑一些有用的进行分析

1,第一个需要分析的就是Activity.java文件中的分发menu按键的方法

  /**
     * Called to process key events.  You can override this to intercept all
     * key events before they are dispatched to the window.  Be sure to call
     * this implementation for key events that should be handled normally.
     *
     * @param event The key event.
     *
     * @return boolean Return true if this event was consumed.
     */
    public boolean dispatchKeyEvent(KeyEvent event) {
        onUserInteraction();

        // Let action bars open menus in response to the menu key prioritized over
        // the window handling it
        if (event.getKeyCode() == KeyEvent.KEYCODE_MENU &&
                mActionBar != null && mActionBar.onMenuKeyEvent(event)) {
           //当menu按键到来时,先判断下actionBar是否为null,如果actionbar不为空再进行处理,即让actionbar响应按键事件  
           
           return true;
        }

        Window win = getWindow();//获取到当前activity的窗口实例
        if (win.superDispatchKeyEvent(event)) {
           //如果acitonbar没有对按键进行处理,则传递给activity所在窗口进行处理 
         return true;
        }
        View decor = mDecor;//先介绍一下,activity的布局的根节点为DecorView,在这里获取到activity的根节点
        if (decor == null) decor = win.getDecorView();
      //如果actionbar没有处理event,window窗口也没处理或者拦截event,则传递给view进行处理  
      return event.dispatch(this, decor != null
                ? decor.getKeyDispatcherState() : null, this);
    }

处理分发按键事件时会调用,用户也可以自己覆写,来达到按自己的意愿处理按键事件的目的,比如拦截按键传递给窗口,view等。 通过以上方法的分析可以总结出,一个menu事件在传递给activity后,如果不是menu事件就会直接交给window会向下传递,有三方可能进行处理 actionbar window view 这三个优先级由高到低,也就是说,menu事件会首先传递给actionbar,如果actionbar进行了处理并且将事件拦截下来不派发给窗口,那么menu事件到actionbar处理之后就结束了。反之则会向window和view进行传递。 2,流程中第二个值得分析的就在ActionMenuPresenter.java中

/**
     * Display the overflow menu if one is present.
     * @return true if the overflow menu was shown, false otherwise.
     */
    public boolean showOverflowMenu() {
        if (mReserveOverflow && !isOverflowMenuShowing() && mMenu != null && mMenuView != null &&
                mPostedOpenRunnable == null && !mMenu.getNonActionItems().isEmpty()) {

          //if条件进行了以下几个判断,mReserveOverflow判断了是否显示overflow按钮,isOverflowMenuShowing表示了菜单项的popupwindow是否正在显示
          //,以及要打开菜单项的进程是否已经初始化,菜单项是否不是空

            //初始化popupwindow对象
           OverflowPopup popup = new OverflowPopup(mContext, mMenu, mOverflowButton, true);
           开启线程,加载popupwindow 
          mPostedOpenRunnable = new OpenOverflowRunnable(popup);
            // Post this for later; we might still need a layout for the anchor to be right.
            ((View) mMenuView).post(mPostedOpenRunnable);

            // ActionMenuPresenter uses null as a callback argument here
            // to indicate overflow is opening.
            super.onSubMenuSelected(null);

            return true;
        }
        return false;
    }

总结下来就是,该方法先对一些必要的条件做了一些判断,比如menu是否存在,menu菜单选项是否为空,menu的popup是否已经弹出,或者正在弹出,然后在进行popup对象的实例化,并开启加载popup的线程。

private class OpenOverflowRunnable implements Runnable {
        private OverflowPopup mPopup;

        public OpenOverflowRunnable(OverflowPopup popup) {
            mPopup = popup;
        }

        public void run() {
            mMenu.changeMenuMode();
            final View menuView = (View) mMenuView;
            if (menuView != null && menuView.getWindowToken() != null && mPopup.tryShow()) {
                mOverflowPopup = mPopup;
            }
            mPostedOpenRunnable = null;
        }
    }

在加载线程中修改menu的状态模式,并且试着去弹出popup,mPopup.tryShow(); 到这里menu按下从activity分发到popup的弹起就分析完了

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Android四大组件完全解析(二)---Service

    Service两大功能 : 当应用程序不与用户交互时,运行一些需要长时间运行的操作 为其他应用提供一些功能(提供能够跨进程调用的功能) Service的配置:...

    fanfan
  • 闲叙蓝牙OPP(二)---文件传输BluetoothOppService专讲

    从上文可以看出,文件插入db后直接就是BluetoothOppService(下文会缩写成BtOppService)的处理了,在BtOppService中建立传...

    fanfan
  • Android7.1.1系统设置默认值大全

    1,是否有默认值 在寻找一个开关的默认值时,首先要明白一点,该开关是否存在默认值,以及该开关状态是否有状态保存(一般状态存储在settings的db中)。 ...

    fanfan
  • 深入了解MD4,MD5,SHA哈希密码算法与破解技术

    密码(password)是最广泛使用的认证系统之一,防止未经授权的用户访问系统,无论是离线还是在线。在大多数系统中,密码是通过加密存储的,以便为每个用户提供安全...

    HACK学习
  • Boltdb源码分析(一)-------page结构

    本文公众号文章链接:https://mp.weixin.qq.com/s/YoRJw_vkAK0aBTN6-HK0qw

    月牙寂道长
  • 死磕 java集合之ConcurrentHashMap源码分析(一)

    ConcurrentHashMap是HashMap的线程安全版本,内部也是使用(数组 + 链表 + 红黑树)的结构来存储元素。

    彤哥
  • 各种 IntelliJ IDEA 酷炫插件推荐

    今天介绍一下IDEA的一些炫酷的插件,IDEA强大的插件库,不仅能给我们带来一些开发的便捷,还能体现我们的与众不同。

    芋道源码
  • Settings -> Plugins 原

    Free Mybatis Plugins    (*mapper.java-- *mapper.xml)

    wuweixiang
  • Java程序员必备的Intellij插件

    如果你是初学者,或者是自学者!你可以加小编微信(xxf960326)!小编可以给你学习上,工作上的一些建议以及可以给你(免费)提供学习资料!最重要我们还可以交个...

    Java学习
  • Java程序员必备的11大Intellij插件

    链接:https://www.jianshu.com/p/686ba0ae4ac2

    Java学习

扫码关注云+社区

领取腾讯云代金券