[英]Swing, Passive View and Long running tasks
我正在嘗試實現基於被動 視圖的gui系統。 基本上我想保持我的視圖實現(實際包含swing代碼的部分)最小化,並在我的Presenter類中完成大部分工作。 演示者應該不依賴於搖擺,也應該“運行節目”,即告訴視圖要做什么而不是反過來。
在處理長時間運行的任務時,我遇到了問題,而且一般情況下線程分離。 我希望GUI更新在EDT上運行,並且演示者邏輯在不同的線程上運行。 如果我希望演示者更新GUI的某些部分,這很容易,我寫的是這樣的:
public interface View {
void setText(String text);
}
public class Presenter {
View view;
...
public void setTextInVIew() {
view.setText("abc");
}
}
public class MyFrame implements View {
JTextField textField;
...
public void setText(final String text) {
SwingUtilities.InvokeLater(new Runnable() {
public void run() {
textField.setText(text);
}
});
}
}
但是,當GUI要通知演示者某些操作已經發生時,我想在不同的線程中切換出EDT對它做出反應:
public class Presenter {
...
public void buttonPressed() {
// shouldn't run on EDT
}
}
public class MyFrame implements View {
JButton button;
public MyFrame() {
...
button.addActionListener(new ActionListener() {
@Override public void actionPerformed(ActionEvent e) {
presenter.ButtonPressed();
}
});
}
}
因為actionPerformed代碼是從EDT運行的,所以presenter.buttonPressed也是如此。 我知道swing有SwingWorker的概念 - 在不同的線程中運行任務,但是看起來我必須將swing代碼插入到我的演示者中,並且視圖正在運行show。 任何想法如何解決這個問題?
您可以執行以下操作,這將保持您的GUI代碼到位,並簡單地執行工作以退出EDT:
button.addActionListener(new ActionListener() {
@Override public void actionPerformed(ActionEvent e) {
SwingWorker sw = new SwingWorker() {
public Object doInBackground(){
presenter.ButtonPressed();
return null;
}
};
sw.execute();
}
});
您可能對Task API感興趣以避免所有樣板。 否則,akf的解決方案看起來很好(雖然不需要為SwingWorker創建變量,但您可以新建並執行匿名變量)。
其他人概述的SwingWorker解決方案的另一種方法是使用具有線程親和力的事件總線。 我實際上認為這可能是你想要的解耦類型的最佳選擇。
退房: EventBus
還有其他總線架構的實現,但EventBus很受歡迎。
- 更新 -
所以EventBus將提供一種從非EDT到EDT的非常簡潔的代理方式(比大量的對SwingUtilities.invokeLater()的顯式調用要好很多 - 但基本上做同樣的事情。雖然EventBus能夠捆綁許多通知並讓它們在單個EDT可運行中命中,因此性能會更好)。
但這並沒有解決從EDT代理事件並讓它們在工作線程上運行的需要。 EventBus中有一個ThreadSafeEventService類可以用作這種野獸的基礎 - 它可以與ExecutorService結合,例如,為某些監聽器處理某些事件注冊。
我想這對我來說關鍵在於無論你想出什么解決方案,都應該嘗試將旋轉封裝在EDT上。
順便說一句 - 你在這里問的問題與微軟的公寓線程模型非常相似。
好的 - 我還有另一種選擇: 旋轉
最終,所有這些解決方案都是線程之間的代理調用。 我認為我們的目標是找到一個不需要大量樣板代碼的解決方案。 例如,您可以連接所有偵聽器,以便檢查它們是否在適當的工作線程上,然后代理到ExecutorService(如果不是)。 但那是一個很大的麻煩。 更好的方法是在業務和視圖對象之間的層中進行代理 - 綁定/偵聽器/您想要將其稱為層的任何內容。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.