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

站在用戶(hù)的角度思考問(wèn)題,與客戶(hù)深入溝通,找到興縣網(wǎng)站設(shè)計(jì)與興縣網(wǎng)站推廣的解決方案,憑借多年的經(jīng)驗(yàn),讓設(shè)計(jì)與互聯(lián)網(wǎng)技術(shù)結(jié)合,創(chuàng)造個(gè)性化、用戶(hù)體驗(yàn)好的作品,建站類(lèi)型包括:成都網(wǎng)站建設(shè)、成都網(wǎng)站制作、企業(yè)官網(wǎng)、英文網(wǎng)站、手機(jī)端網(wǎng)站、網(wǎng)站推廣、域名注冊(cè)、網(wǎng)站空間、企業(yè)郵箱。業(yè)務(wù)覆蓋興縣地區(qū)。
本篇內(nèi)容:
- 項(xiàng)目或模塊事件監(jiān)聽(tīng):在模塊或者整個(gè)項(xiàng)目發(fā)生改變時(shí),通過(guò)事件監(jiān)聽(tīng)做出反應(yīng),如項(xiàng)目新增了一個(gè)模塊或是刪除了某個(gè)模塊;
- 文件編輯事件監(jiān)聽(tīng):在Java代碼文件編輯時(shí),通過(guò)事件監(jiān)聽(tīng)能夠知道哪個(gè)類(lèi)的代碼改變了,此時(shí)后臺(tái)就可以刷新一些數(shù)據(jù)的緩存;
如何監(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è),配置代碼如下:
- topic="com.intellij.openapi.project.ProjectManagerListener"/>
- topic:填寫(xiě)事件主題,類(lèi)似于消息中間件中的Topic,只不過(guò)這里填寫(xiě)的是事件監(jiān)聽(tīng)器的接口類(lèi)名;
- class:添加接口的實(shí)現(xiàn)類(lèi)名;
當(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類(lèi)的源碼,有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
modules, @NotNull Function 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接口定義的方法較多,可以分為兩類(lèi)事件,一類(lèi)是before事件、一類(lèi)是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)用,例如修改文件名;
最后
“編寫(xiě)一個(gè)IDEA插件”系列暫時(shí)就寫(xiě)這些,因?yàn)閷?duì)這方面感興趣的讀者可能比對(duì)匯編語(yǔ)言感興趣的讀者還少。其實(shí)這幾篇分析的也是筆者寫(xiě)插件過(guò)程中用到的一些筆者認(rèn)為非常重要的知識(shí)點(diǎn),當(dāng)然還有很多沒(méi)分享,如果要繼續(xù)寫(xiě),估計(jì)還可以寫(xiě)幾篇,但看到上篇的閱讀量就沒(méi)動(dòng)力繼續(xù)寫(xiě)下去了。
參考:
- intellij-platform-plugin-template的項(xiàng)目管理監(jiān)聽(tīng)器注冊(cè):https://sourcegraph.com/github.com/JetBrains/intellij-platform-plugin-template@main/-/blob/src/main/resources/META-INF/plugin.xml#L17:55
- 接收有關(guān)項(xiàng)目結(jié)構(gòu)變更的通知:https://jetbrains.org/intellij/sdk/docs/reference_guide/project_model/project.html?search=projectClosingBeforeSave
本文轉(zhuǎn)載自微信公眾號(hào)「Java藝術(shù)」,可以通過(guò)以下二維碼關(guān)注。轉(zhuǎn)載本文請(qǐng)聯(lián)系Java藝術(shù)公眾號(hào)。
當(dāng)前名稱(chēng):編寫(xiě)一個(gè)IDEA插件之:事件監(jiān)聽(tīng)
本文路徑:http://www.5511xx.com/article/ccisjhc.html


咨詢(xún)
建站咨詢(xún)
