新聞中心
事件監(jiān)聽,我們最熟悉不過的就是開發(fā)APP時,監(jiān)聽按鈕點擊事件、手指觸摸及移動事件、網(wǎng)絡狀態(tài)事件等等。事件監(jiān)聽大多通過觀察者模式實現(xiàn),首先API調用者不需要知道后臺是如何檢測出網(wǎng)絡狀態(tài)不可用的,而只需要向系統(tǒng)注冊一個監(jiān)聽器,當網(wǎng)絡狀態(tài)發(fā)生改變時,由系統(tǒng)回調給監(jiān)聽器。

站在用戶的角度思考問題,與客戶深入溝通,找到興縣網(wǎng)站設計與興縣網(wǎng)站推廣的解決方案,憑借多年的經驗,讓設計與互聯(lián)網(wǎng)技術結合,創(chuàng)造個性化、用戶體驗好的作品,建站類型包括:成都網(wǎng)站建設、成都網(wǎng)站制作、企業(yè)官網(wǎng)、英文網(wǎng)站、手機端網(wǎng)站、網(wǎng)站推廣、域名注冊、網(wǎng)站空間、企業(yè)郵箱。業(yè)務覆蓋興縣地區(qū)。
本篇內容:
- 項目或模塊事件監(jiān)聽:在模塊或者整個項目發(fā)生改變時,通過事件監(jiān)聽做出反應,如項目新增了一個模塊或是刪除了某個模塊;
- 文件編輯事件監(jiān)聽:在Java代碼文件編輯時,通過事件監(jiān)聽能夠知道哪個類的代碼改變了,此時后臺就可以刷新一些數(shù)據(jù)的緩存;
如何監(jiān)聽項目或模塊改變事件
首先是項目級別的事件監(jiān)聽。添加一個項目管理事件監(jiān)聽器,我們需要實現(xiàn)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的區(qū)別在于,projectClosed在項目已經關閉時被回調,在ProjectManagerImpl#closeProject方法執(zhí)行到最后一行代碼時被調用。
有了項目管理事件監(jiān)聽器之后,我們如何注冊該監(jiān)聽器呢?
有兩種方法,一種是代碼方式注冊,一種是在plugin.xml插件配置文件中注冊。
代碼方式注冊可調用ProjectManager.getInstance().addProjectManagerListener();方法注冊,但這種方式注冊有一個弊端,就是無法監(jiān)聽到項目打開事件,projectOpened方法不會被調用,應該在我們能夠調用該方法注冊監(jiān)聽器時,項目實際已經打開了。
所以注冊項目管理監(jiān)聽器我們只能通過修改plugin.xml配置文件方式注冊,配置代碼如下:
- topic="com.intellij.openapi.project.ProjectManagerListener"/>
- topic:填寫事件主題,類似于消息中間件中的Topic,只不過這里填寫的是事件監(jiān)聽器的接口類名;
- class:添加接口的實現(xiàn)類名;
當我們給IDEA注冊自定義的項目管理事件監(jiān)聽器后,我們就可以通過項目管理事件監(jiān)聽器注冊其它的事件監(jiān)聽器,例如注冊模塊監(jiān)聽事件,這是因為模塊的事件觸發(fā)在項目打開事件觸發(fā)之后才會觸發(fā)。因此,在projectOpened方法中可注冊任何其它的事件監(jiān)聽器。
注冊模塊事件監(jiān)聽器代碼如下:
- project.getMessageBus().connect()
- .subscribe(ProjectTopics.MODULES, new ModuleListener(){});
subscribe方法需要兩個參數(shù):
- topic:主題,可選值參見ProjectTopics類的源碼,有PROJECT_ROOTS和MODULES;
- handler:事件處理器、監(jiān)聽器,當topic為MODULES時,要求傳遞一個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
modules, @NotNull Function oldNameProvider) { - }
- }
- moduleAdded:添加模塊完成時被調用;
- beforeModuleRemoved:模塊被移除之前被調用;
- moduleRemoved:模塊被移除時被調用;
- modulesRenamed:模塊修改名字時被調用;
如何監(jiān)聽文件編輯事件
通過前面兩篇的學習,我們已經了解什么是PSI,知道一個文件對應一個PsiFile,一個PsiFile本身也是一個PsiElement,由許多的PsiElement構成,每個PsiElement也都可以有子PsiElement。
因此,監(jiān)聽文件改變事件其實就是監(jiān)聽PSI樹的結構改變事件,我們需要通過PsiManager注冊PsiTreeChangeListener,代碼如下。
- PsiManager.getInstance(project).addPsiTreeChangeListener(
- new PsiTreeChangeListener() {
- // .....
- }, FILES::clear);
至于注冊時機,視情況而定,可以在Service初始化時注冊,可以在AnAction觸發(fā)時注冊,也可以在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:子元素被替換時被調用,觸發(fā)childReplaced事件也會伴隨著childrenChanged事件;
- childAdded:子元素添加時被調用,觸發(fā)childAdded事件時也會伴隨著childReplaced、childrenChanged或事件;
- childRemoved:子元素移除時被調用,觸發(fā)childRemoved事件也會伴隨著childReplaced、childrenChanged事件;
- propertyChanged:屬性改變時被調用,例如修改文件名;
最后
“編寫一個IDEA插件”系列暫時就寫這些,因為對這方面感興趣的讀者可能比對匯編語言感興趣的讀者還少。其實這幾篇分析的也是筆者寫插件過程中用到的一些筆者認為非常重要的知識點,當然還有很多沒分享,如果要繼續(xù)寫,估計還可以寫幾篇,但看到上篇的閱讀量就沒動力繼續(xù)寫下去了。
參考:
- intellij-platform-plugin-template的項目管理監(jiān)聽器注冊: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
本文轉載自微信公眾號「Java藝術」,可以通過以下二維碼關注。轉載本文請聯(lián)系Java藝術公眾號。
網(wǎng)站標題:編寫一個IDEA插件之:事件監(jiān)聽
文章轉載:http://www.5511xx.com/article/ccisjhc.html


咨詢
建站咨詢
