事件监听,我们最熟悉不过的就是开发APP时,监听按钮点击事件、手指触摸及移动事件、网络状态事件等等。事件监听大多通过观察者模式实现,首先API调用者不需要知道后台是如何检测出网络状态不可用的,而只需要向系统注册一个监听器,当网络状态发生改变时,由系统回调给监听器。

本篇内容:

  • 项目或模块事件监听:在模块或者整个项目发生改变时,通过事件监听做出反应,如项目新增了一个模块或是删除了某个模块;

  • 文件编辑事件监听:在Java代码文件编辑时,通过事件监听能够知道哪个类的代码改变了,此时后台就可以刷新一些数据的缓存;

如何监听项目或模块改变事件

首先是项目级别的事件监听。添加一个项目管理事件监听器,我们需要实现ProjectManagerListener接口,该接口有四个方法,其源码如下。

public interface ProjectManagerListener extends EventListener {default void projectOpened(@NotNull Project project) {}default void projectClosed(@NotNull Project project) {}default void projectClosing(@NotNull Project project) {}default void projectClosingBeforeSave(@NotNull Project project) {}
}
  • projectOpened:该方法在项目打开时被回调;

  • projectClosingBeforeSave:在关闭项目时,开始保存项目之前被回调,或者说是在调用FileDocumentManager#saveAllDocuments方法保存所有文件之前被调用;

  • projectClosing:在projectClosingBeforeSave方法之后被回调;

  • projectClosed:与projectClosing的区别在于,projectClosed在项目已经关闭时被回调,在ProjectManagerImpl#closeProject方法执行到最后一行代码时被调用。

有了项目管理事件监听器之后,我们如何注册该监听器呢?

有两种方法,一种是代码方式注册,一种是在plugin.xml插件配置文件中注册。

代码方式注册可调用ProjectManager.getInstance().addProjectManagerListener();方法注册,但这种方式注册有一个弊端,就是无法监听到项目打开事件,projectOpened方法不会被调用,应该在我们能够调用该方法注册监听器时,项目实际已经打开了。

所以注册项目管理监听器我们只能通过修改plugin.xml配置文件方式注册,配置代码如下:

<applicationListeners><listener class="com.msyc.ycpay.plugin.listener.MyProjectManagerListener"topic="com.intellij.openapi.project.ProjectManagerListener"/>
</applicationListeners>
  • topic:填写事件主题,类似于消息中间件中的Topic,只不过这里填写的是事件监听器的接口类名;

  • class:添加接口的实现类名;

当我们给IDEA注册自定义的项目管理事件监听器后,我们就可以通过项目管理事件监听器注册其它的事件监听器,例如注册模块监听事件,这是因为模块的事件触发在项目打开事件触发之后才会触发。因此,在projectOpened方法中可注册任何其它的事件监听器。

注册模块事件监听器代码如下:

project.getMessageBus().connect()
.subscribe(ProjectTopics.MODULES, new ModuleListener(){});

subscribe方法需要两个参数:

  • topic:主题,可选值参见ProjectTopics类的源码,有PROJECT_ROOTSMODULES

  • handler:事件处理器、监听器,当topicMODULES时,要求传递一个ModuleListener

ModuleListener接口的定义如下:

public interface ModuleListener extends EventListener {default void moduleAdded(@NotNull Project project, @NotNull Module module) {}default void beforeModuleRemoved(@NotNull Project project, @NotNull Module module) {}default void moduleRemoved(@NotNull Project project, @NotNull Module module) {}default void modulesRenamed(@NotNull Project project, @NotNull List<Module> modules, @NotNull Function<Module, String> oldNameProvider) {}
}
  • moduleAdded:添加模块完成时被调用;

  • beforeModuleRemoved:模块被移除之前被调用;

  • moduleRemoved:模块被移除时被调用;

  • modulesRenamed:模块修改名字时被调用;

如何监听文件编辑事件

通过前面两篇的学习,我们已经了解什么是PSI,知道一个文件对应一个PsiFile,一个PsiFile本身也是一个PsiElement,由许多的PsiElement构成,每个PsiElement也都可以有子PsiElement

因此,监听文件改变事件其实就是监听PSI树的结构改变事件,我们需要通过PsiManager注册PsiTreeChangeListener,代码如下。

PsiManager.getInstance(project).addPsiTreeChangeListener(new PsiTreeChangeListener() {// .....}, FILES::clear);

至于注册时机,视情况而定,可以在Service初始化时注册,可以在AnAction触发时注册,也可以在projectOpened事件方法中注册。

PsiTreeChangeListener接口定义的方法较多,可以分为两类事件,一类是before事件、一类是after事件,接口源码如下。

public interface PsiTreeChangeListener extends EventListener {void beforeChildAddition(@NotNull PsiTreeChangeEvent event);void beforeChildRemoval(@NotNull PsiTreeChangeEvent event);void beforeChildReplacement(@NotNull PsiTreeChangeEvent event);void beforeChildMovement(@NotNull PsiTreeChangeEvent event);void beforeChildrenChange(@NotNull PsiTreeChangeEvent event);void beforePropertyChange(@NotNull PsiTreeChangeEvent event);void childAdded(@NotNull PsiTreeChangeEvent event);void childRemoved(@NotNull PsiTreeChangeEvent event);void childReplaced(@NotNull PsiTreeChangeEvent event);void childrenChanged(@NotNull PsiTreeChangeEvent event);void childMoved(@NotNull PsiTreeChangeEvent event);void propertyChanged(@NotNull PsiTreeChangeEvent event);
}
  • childrenChanged:子元素内容改变时被调用;

  • childReplaced:子元素被替换时被调用,触发childReplaced事件也会伴随着childrenChanged事件;

  • childAdded:子元素添加时被调用,触发childAdded事件时也会伴随着childReplacedchildrenChanged或事件;

  • childRemoved:子元素移除时被调用,触发childRemoved事件也会伴随着childReplacedchildrenChanged事件;

  • propertyChanged:属性改变时被调用,例如修改文件名;

最后

“编写一个IDEA插件”系列暂时就写这些,因为对这方面感兴趣的读者可能比对汇编语言感兴趣的读者还少。其实这几篇分析的也是笔者写插件过程中用到的一些笔者认为非常重要的知识点,当然还有很多没分享,如果要继续写,估计还可以写几篇,但看到上篇的阅读量就没动力继续写下去了。

参考:

  • intellij-platform-plugin-template的项目管理监听器注册:https://sourcegraph.com/github.com/JetBrains/intellij-platform-plugin-template@main/-/blob/src/main/resources/META-INF/plugin.xml#L17:55

  • 接收有关项目结构变更的通知:https://jetbrains.org/intellij/sdk/docs/reference_guide/project_model/project.html?search=projectClosingBeforeSave

编写一个IDEA插件之:事件监听相关推荐

  1. java 监听鼠标点击_java 事件监听 - 鼠标

    java 事件监听 - 鼠标 //事件监听 //鼠标事件监听 //鼠标事件监听有两个实现接口 //1.MouseListener 普通的鼠标操作 //2.MouseMotionListener 鼠标的 ...

  2. 事件监听watch框架vue2.x与3.x都适用

    前言: 目前正在学习vue或者对vue部分使用不太熟悉的可以跟着的我文章,打开编辑器,安装vue-cli一步步的练习,不会安装vue-cli脚手架的小伙伴可以先看这篇文章https://blog.cs ...

  3. 关于Openlayers Overlay事件监听的一个坑

    一.问题产生: 我使用Overlay创建标绘操作的小方块元素,如下代码和如图. 然后我监听小方块的mousedown事件.用原始的事件监听: element.addEventListener('mou ...

  4. 安卓Android绘制一个信息填写页面,使用了三种事件监听方法

    先上效果图片: 第一种,匿名内部类 //设置提交按钮监听submitButton.setOnClickListener(new View.OnClickListener() {@Overridepub ...

  5. 编写一个VSCode插件

    原文链接: 编写一个VSCode插件 - 愧怍的小站 自从使用过 VSCode 后就再也离不开 VSCode,其轻量的代码编辑器与诸多插件让多数开发者爱不释手.同样我也不例外,一年前的我甚至还特意买本 ...

  6. Java中事件监听机制

    Java中事件监听机制 一.事件监听机制的定义 要想了解Java中的事件监听机制,首先就要去了解一下在Java中事件是怎样去定义的呢!在使用Java编写好一个界面后,我们就会对界面进行一些操作,比如, ...

  7. 13、Java Swing事件监听:事件处理模型和事件监听器

    事件表示程序和用户之间的交互,例如在文本框中输入,在列表框或组合框中选择,选中复选框和单选框,单击按钮等.事件处理表示程序对事件的响应,对用户的交互或者说对事件的处理是事件处理程序完成的. 当事件发生 ...

  8. java swing事件监听_Java swing(awt):事件监听机制的实现原理+简单示例

    (1)实现原理 事件监听机制的实现: 参考图:事件模型_ActionEvent 为了节省资源,系统无法对某个事件进行实时的监听.故实现的机制是当发生某个事件后,处理代码将被自动运行,类似钩子一般.(回 ...

  9. java监听机制_详解java的事件监听机制和观察者设计模式

    首先说说监听器: 监听器就是一个实现特定接口的普通java程序,这个程序专门用于监听另一个java对象的方法调用或属性改变,当被监听对象发生上述事件后,监听器某个方法将立即被执 行. java的事件监 ...

最新文章

  1. 从事IT行业需要了解到
  2. java数据结构-HashMap
  3. 【排序函数讲解】sort-C++
  4. Octave 作图 无响应
  5. lock mysql unlock_MySql中Lock命令和unlock命令
  6. java servlet 注册登录,JSP+JavaBean+Servlet实现用户登录与注册
  7. 求1000以内的素数c语言程序设计,C语言程序设计报告 C 实验名称 计算并输出1000以内最大的10个素数以及它们的和.doc...
  8. Windows Server 2008 RC1标准版
  9. 吴恩达机器学习笔记目录
  10. 我为什么从 Google 辞职,开始为自己工作?
  11. php 处理树形数据,php设计模式之组合模式——处理树形结构数据
  12. 【typescript】infer的理解与使用
  13. 取消微信抢票的服务器,微信抢票怎么取消?
  14. 路由器设置多WAN口要点技巧
  15. 取消桌面上计算机控制板网络三个系统图标,大神处置win10系统桌面图标“计算机 控制面板 网络”怎么不见了的解决方的步骤...
  16. Microsoft Orleans 之 入门指南
  17. [MATLAB]河道水流量的估算问题
  18. whois命令_WHOIS使用Whois搜索
  19. 火狐、chrome浏览器过滤网页广告设置过程
  20. 【C语言】C语言复习笔记

热门文章

  1. English--倒装句
  2. 曲师大教务系统服务器,曲阜师范大学教务系统
  3. Android 应用链接详解
  4. Centos7.5-文件的基本管理和XFS文件系统备份恢复
  5. mysql 公历变农历_SQLServer公历转农历函数(1900年-2049年)
  6. Flask结合werobot实现微信公众号自动回复
  7. 基于Java(Jsp+servelet+Javabean)+MySQL实现图书管理系统【100010229】
  8. Android7.0 init进程源码分析
  9. ERROR 2003 ( HY000 ) : Can ‘t connect to MySQL server on ‘ xxx.xxx.xxx.xxx ‘,
  10. octave java_Octave快速入门