溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

編寫(xiě)一個(gè)IDEA插件之怎么實(shí)現(xiàn)事件監(jiān)聽(tīng)

發(fā)布時(shí)間:2021-10-26 15:48:54 來(lái)源:億速云 閱讀:439 作者:iii 欄目:開(kāi)發(fā)技術(shù)

本篇內(nèi)容主要講解“編寫(xiě)一個(gè)IDEA插件之怎么實(shí)現(xiàn)事件監(jiān)聽(tīng)”,感興趣的朋友不妨來(lái)看看。本文介紹的方法操作簡(jiǎn)單快捷,實(shí)用性強(qiáng)。下面就讓小編來(lái)帶大家學(xué)習(xí)“編寫(xiě)一個(gè)IDEA插件之怎么實(shí)現(xiàn)事件監(jiān)聽(tīng)”吧!

如何監(jiān)聽(tīng)項(xiàng)目或模塊改變事件

首先是項(xiàng)目級(jí)別的事件監(jiān)聽(tīng)。添加一個(gè)項(xiàng)目管理事件監(jiān)聽(tīng)器,我們需要實(shí)現(xiàn)ProjectManagerListener接口,該接口有四個(gè)方法,其源碼如下。

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:該方法在項(xiàng)目打開(kāi)時(shí)被回調(diào);

  • projectClosingBeforeSave:在關(guān)閉項(xiàng)目時(shí),開(kāi)始保存項(xiàng)目之前被回調(diào),或者說(shuō)是在調(diào)用FileDocumentManager#saveAllDocuments方法保存所有文件之前被調(diào)用;

  • projectClosing:在projectClosingBeforeSave方法之后被回調(diào);

  • projectClosed:與projectClosing的區(qū)別在于,projectClosed在項(xiàng)目已經(jīng)關(guān)閉時(shí)被回調(diào),在ProjectManagerImpl#closeProject方法執(zhí)行到最后一行代碼時(shí)被調(diào)用。

有了項(xiàng)目管理事件監(jiān)聽(tīng)器之后,我們?nèi)绾巫?cè)該監(jiān)聽(tīng)器呢?

有兩種方法,一種是代碼方式注冊(cè),一種是在plugin.xml插件配置文件中注冊(cè)。

代碼方式注冊(cè)可調(diào)用ProjectManager.getInstance().addProjectManagerListener();方法注冊(cè),但這種方式注冊(cè)有一個(gè)弊端,就是無(wú)法監(jiān)聽(tīng)到項(xiàng)目打開(kāi)事件,projectOpened方法不會(huì)被調(diào)用,應(yīng)該在我們能夠調(diào)用該方法注冊(cè)監(jiān)聽(tīng)器時(shí),項(xiàng)目實(shí)際已經(jīng)打開(kāi)了。

所以注冊(cè)項(xiàng)目管理監(jiān)聽(tīng)器我們只能通過(guò)修改plugin.xml配置文件方式注冊(cè),配置代碼如下:

<applicationListeners>     <listener class="com.msyc.ycpay.plugin.listener.MyProjectManagerListener"               topic="com.intellij.openapi.project.ProjectManagerListener"/> </applicationListeners>
  • topic:填寫(xiě)事件主題,類似于消息中間件中的Topic,只不過(guò)這里填寫(xiě)的是事件監(jiān)聽(tīng)器的接口類名;

  • class:添加接口的實(shí)現(xiàn)類名;

當(dāng)我們給IDEA注冊(cè)自定義的項(xiàng)目管理事件監(jiān)聽(tīng)器后,我們就可以通過(guò)項(xiàng)目管理事件監(jiān)聽(tīng)器注冊(cè)其它的事件監(jiān)聽(tīng)器,例如注冊(cè)模塊監(jiān)聽(tīng)事件,這是因?yàn)槟K的事件觸發(fā)在項(xiàng)目打開(kāi)事件觸發(fā)之后才會(huì)觸發(fā)。因此,在projectOpened方法中可注冊(cè)任何其它的事件監(jiān)聽(tīng)器。

注冊(cè)模塊事件監(jiān)聽(tīng)器代碼如下:

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

subscribe方法需要兩個(gè)參數(shù):

  • topic:主題,可選值參見(jiàn)ProjectTopics類的源碼,有PROJECT_ROOTS和MODULES;

  • handler:事件處理器、監(jiān)聽(tīng)器,當(dāng)topic為MODULES時(shí),要求傳遞一個(gè)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:添加模塊完成時(shí)被調(diào)用;

  • beforeModuleRemoved:模塊被移除之前被調(diào)用;

  • moduleRemoved:模塊被移除時(shí)被調(diào)用;

  • modulesRenamed:模塊修改名字時(shí)被調(diào)用;

如何監(jiān)聽(tīng)文件編輯事件

通過(guò)前面兩篇的學(xué)習(xí),我們已經(jīng)了解什么是PSI,知道一個(gè)文件對(duì)應(yīng)一個(gè)PsiFile,一個(gè)PsiFile本身也是一個(gè)PsiElement,由許多的PsiElement構(gòu)成,每個(gè)PsiElement也都可以有子PsiElement。

因此,監(jiān)聽(tīng)文件改變事件其實(shí)就是監(jiān)聽(tīng)PSI樹(shù)的結(jié)構(gòu)改變事件,我們需要通過(guò)PsiManager注冊(cè)PsiTreeChangeListener,代碼如下。

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

至于注冊(cè)時(shí)機(jī),視情況而定,可以在Service初始化時(shí)注冊(cè),可以在AnAction觸發(fā)時(shí)注冊(cè),也可以在projectOpened事件方法中注冊(cè)。

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:子元素內(nèi)容改變時(shí)被調(diào)用;

  • childReplaced:子元素被替換時(shí)被調(diào)用,觸發(fā)childReplaced事件也會(huì)伴隨著childrenChanged事件;

  • childAdded:子元素添加時(shí)被調(diào)用,觸發(fā)childAdded事件時(shí)也會(huì)伴隨著childReplaced、childrenChanged或事件;

  • childRemoved:子元素移除時(shí)被調(diào)用,觸發(fā)childRemoved事件也會(huì)伴隨著childReplaced、childrenChanged事件;

  • propertyChanged:屬性改變時(shí)被調(diào)用,例如修改文件名;

到此,相信大家對(duì)“編寫(xiě)一個(gè)IDEA插件之怎么實(shí)現(xiàn)事件監(jiān)聽(tīng)”有了更深的了解,不妨來(lái)實(shí)際操作一番吧!這里是億速云網(wǎng)站,更多相關(guān)內(nèi)容可以進(jìn)入相關(guān)頻道進(jìn)行查詢,關(guān)注我們,繼續(xù)學(xué)習(xí)!

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI