我們剛剛已經看到如何在 Runnable 中進行資源變更批次作業(資源變更批次作業)。讓我們再看看這件事的另一面。如果要在您的外掛程式執行時追蹤工作區發生的所有變更該怎麼做?您可以將 IResourceChangeListener 登錄於工作區。您的接聽器會透過說明變更的 IResourceChangeEvent 物件收到變更通知。
首先,您必須向工作區登錄資源變更接聽器。
IResourceChangeListener listener = new MyResourceChangeReporter(); ResourcesPlugin.getWorkspace().addResourceChangeListener( listener, IResourceChangeEvent.POST_CHANGE);
如果工作區資源做過修正,您的接聽器便會收到通知。修改資源的資源 API 方法將 這些事件觸發為它們記錄行為的一部分。資源 API 的方法註解明確地陳述它是 否觸發了資源變更事件。例如,下列併入 IFile.setContents() 註解中:
這個方法變更資源;這些變更將在後續的資源變更事件中報告,包括對這個檔案內容 已變更的指示。
建立、除去或變更資源的方法通常會觸發這些事件。讀取但不寫入資源的方法通常不 會觸發這些事件。
資源變更事件說明工作區中發生的變更特性(或變更集)。這個事件包含一個 資源 差異,它說明變更的網路效能。比方說,如果您新增某個資源而稍後在一 個批次變更期間除去了它,該資源不會在差異中出現。
資源差異建構為在工作區根啟動的樹狀結構。資源差異樹狀結構說明這些變更類型:
欲遍訪資源差異樹狀結構,您可以實作 IResourceDeltaVisitor 介面或使用 IResource.getAffectedChildren 來明確地遍訪樹狀結構。資源 差異訪客實作資源差異呼叫的 visit 方法,因為它列舉樹狀結構中每一個變 更。
附註: 對資源階段作業內容或資源持續性內容所做的變更,不會在資源差異中識別。
每當工作區有變更(或批次處理的變更集)時,便會傳送資源變更事件。 此外,也會針對某些特定的工作區作業傳送資源變更事件。下表彙總資源變更事件的 類型及報告的時間。
事件類型 |
說明 |
---|---|
PRE_CLOSE |
通知接聽器專案即將關閉。這個事件可用來擷取及儲存專案關閉前記憶體中表示法(例 如,階段作業內容)的必要資訊。(當專案關閉時,便會除去記憶體中表示法)。 在這個事件期間,工作區會被鎖定(無法更新任何資源)。這個事件包含已關閉的 專案。 |
PRE_DELETE |
通知接聽器專案即將除去。這個事件可用來執行清除作業,例如從您外掛程式目錄中除去與專案相關的任何已儲存狀態。在這個事件期間,工作區會被鎖定(無法更 新任何資源)。這個事件包含已除去的專案。 |
PRE_AUTOBUILD |
發生任何自動建置前通知接聽器。當平台偵測到必須發生的自動建置,無論自 動建置是否真的啟用了,都會傳佈這個事件。在這個事件期間,工作區不 會被鎖定(可更新資源)。 這個事件包含一個資源差異,它說明上次報告 POST_CHANGE 事件後所發生的變 更。 |
POST_AUTOBUILD |
在發生任何自動建置後通知接聽器。在平台執行自動建置後,無論自動建置是否真的 啟用了,都會廣播這個事件。在這個事件期間,工作區不會被鎖定( 可更新資源)。 這個事件包含一個資源差異,它說明上次報告 POST_CHANGE 事件後所發生的變 更。 |
POST_CHANGE |
說明上次報告 POST_CHANGE 事件後工作區發生的一組變更。在個別使用資 源變更 API 或在一組批次處理的工作區變更後觸發。也會在完成任何 PRE_AUTOBUILD 或 POST_AUTOBUILD 通知後觸發。 這個事件包含一個資源差異,它說明上次 POST_CHANGE 事件後的網路變更。 在這個事件期間,工作區會被鎖定(無法更新任何資源)。 |
下列範例實作主控台型資源變更接聽器。針對特定事件類型和輸出至主控台的這些事 件相關資訊登錄資源變更接聽器。
IResourceChangeListener listener = new MyResourceChangeReporter(); ResourcesPlugin.getWorkspace().addResourceChangeListener(listener, IResourceChangeEvent.PRE_CLOSE | IResourceChangeEvent.PRE_DELETE | IResourceChangeEvent.PRE_AUTO_BUILD | IResourceChangeEvent.POST_AUTO_BUILD | IResourceChangeEvent.POST_CHANGE);
接聽器檢查每一個事件類型並報告變更的資源和發生的變更種類之相關資訊。 雖然這個範例是設計來顯示一個處理所有源事件類型的一般接聽器,但典型接聽器僅登 錄一種事件類型。
POST_CHANGE 的實作使用可用來造訪資源差異中變更的另一個類別。
import org.eclipse.resources.*;import org.eclipse.runtime.*; public class MyResourceChangeReporter implements IResourceChangeListener { public void resourceChanged(IResourceChangeEvent event) { IResource res = event.getResource(); switch (event.getType()) { case IResourceChangeEvent.PRE_CLOSE: System.out.print("Project "); System.out.print(res.getFullPath()); System.out.println(" is about to close."); break; case IResourceChangeEvent.PRE_DELETE: System.out.print("Project "); System.out.print(res.getFullPath()); System.out.println(" is about to be deleted."); break; case IResourceChangeEvent.POST_CHANGE: System.out.println("Resources have changed."); event.getDelta().accept(new DeltaPrinter()); break; case IResourceChangeEvent.PRE_AUTO_BUILD: System.out.println("Auto build about to run."); event.getDelta().accept(new DeltaPrinter()); break; case IResourceChangeEvent.POST_AUTO_BUILD: System.out.println("Auto build complete."); event.getDelta().accept(new DeltaPrinter()); break; } } }
DeltaPrinter 類別實作 IResourceDeltaVisitor 介面來詢問資源差異。針對資源差異中每一個資源變更呼叫 visit() 方法。 訪客使用回覆值來指示是否應造訪子項資源的差異。
class DeltaPrinter implements IResourceDeltaVisitor { public boolean visit(IResourceDelta delta) { IResource res = delta.getResource(); switch (delta.getKind()) { case IResourceDelta.ADDED: System.out.print("Resource "); System.out.print(res.getFullPath()); System.out.println(" was added."); break; case IResourceDelta.REMOVED" System.out.print("Resource "); System.out.print(res.getFullPath()); System.out.println(" was removed."); break; case IResourceDelta.CHANGED: System.out.print("Resource "); System.out.print(res.getFullPath()); System.out.println(" has changed."); break; } return true; // 造訪子項 } }
進一步資訊可從提供的資源差異取得。下列片段顯示如何實作 IResourceDelta.CHANGED 案例來進一步說明資源變更。
... case IResourceDelta.CHANGED: System.out.print("Resource "); System.out.print(delta.getFullPath()); System.out.println(" has changed."); int flags = delta.getFlags(); if ((flags & IResourceDelta.CONTENT) != 0) { System.out.println("--> Content Change"); } if ((flags & IResourceDelta.REPLACED) != 0) { System.out.println("--> Content Replaced"); } if ((flags & IResourceDelta.MARKERS) != 0) { System.out.println("--> Marker Change"); IMarkerDelta[] markers = delta.getMarkerDeltas(); // 如果對標記有興趣,請檢查這些差異 } break; ...
如果需要資源差異、訪客和標記差異的完整說明,請參考 API 規格的 IResourceDelta 、 IResourceDeltaVisitor 及 IMarkerDelta 。
附註: 當外掛程式啟動時,資源變更接聽器對追蹤資源發生的變更而言非常有用。如果您的外掛程式在啟動碼期間登錄資源變更接聽器,則在啟動外掛程式前可能會觸 發許多資源變更事件。您外掛程式接收的第一個資源變更事件內含的資源差異將不含 外掛程式上次啟動後所做的全部變更。如果您需要追蹤外掛程式活動間所做的變更, 您應該使用針對工作區儲存所提供的支援。這說明於工作區儲存參與中。
附註: 處理期間會觸發某些發生在背景執行緒中的資源變更事件。資源變更接聽器應該是執行緒安全狀態。請參閱執行緒作業問題,以取得 UI 的執行緒安全相關的說明。