如何使用SwingWorker类来实现界面实时强制自动刷新???

时间:2023-01-28 00:22:22
如题。我的基本问题是这样的:现在我开发了一个简单扼微博系统,在客户端是用java swing写的简单界面。服务器没界面。
某个基本功能是查看自己的粉丝对象。先假设A客户端原先没有关注B客户端,所以在B那里是不会显示B有粉丝A的。现在A增加一个关注对象B,我现在可以使A客户端的界面即时自动更新显示A有一个关注对象B,但是B端必须通过我在界面上设置的一个更新按钮去手动刷新自己的粉丝列表。
我想实现的效果是:B端的粉丝列表能够自动实时更新,不一定需要B手动点击更新按钮。

问题:
1、
初步设想使用SwingWorker,但是没有思路?需要在客户端怎么和服务器交互,才能使SwingWorker的doInBackground方法即时获取最新的粉丝对象信息呢?
2、
若不是采用SwingWorker,还有其他什么的解决方案?
急待各位指点迷津,谢谢!

13 个解决方案

#1


1 在客户端使用定时器每隔一定时间检测服务器

2 实时更新需要服务器支持,搜索comet

#2



[Client A] --call--> [Server] --single.cast--> [Client B] --edt.sync--> [GUI]
[Client A] --call--> [Server] --multi.cast--> [Client A & B] --edt.sync--> [GUI]
[Client A] --call--> [Server] --broad.cast--> [All Clients] --edt.sync--> [GUI]

Observer Design Pattern, 客户端监听服务器上任何它感兴趣的改动,
服务器可以选择对某项改动:

single cast : 确定只有一个客户端对改动感兴趣,发给它
multi cast : 客户端通过某种方式订阅一些“组”,订阅也可以是服务器根据客户端的特性来指定,服务器端根据改动的特点发送给相关订阅的客户端组
broad cast : 服务器端的改动通知所有的客户端,客户端自行判断自己是不是感兴趣

不管是哪一种,客户端需要某种线程(如果是RMI那就是client call back),来监听服务器端的改动,然后如果感兴趣,那就向EDT提交事件,刷新UI。( SwingUtilities.invokeLater(...) )


#3


引用 1 楼 huntor 的回复:
1 在客户端使用定时器每隔一定时间检测服务器

2 实时更新需要服务器支持,搜索comet

请问:那是不是还要用SwingWorker呢?

#4


如果服务器与客户端有建立连接,建议你最好使用消息推送的方式
服务器端有新用户动态,推送给对此相关的客户端!
也可以使用JMS订阅发布方式!

总之办法有很多,跟SwingWorker好像关系不大啊~~~~

#5


引用 4 楼 jia20003 的回复:
如果服务器与客户端有建立连接,建议你最好使用消息推送的方式
服务器端有新用户动态,推送给对此相关的客户端!
也可以使用JMS订阅发布方式!

总之办法有很多,跟SwingWorker好像关系不大啊~~~~

我现在使用java socket通信,很基础的。如果采用您说的“服务器推”技术,怎么更改我写的socket呢?那个貌似使用http servlet的哦。。。还是所有有关socket的代码都不能用了,要重写?
谢谢!

#6


引用 1 楼 huntor 的回复:
1 在客户端使用定时器每隔一定时间检测服务器

2 实时更新需要服务器支持,搜索comet

我现在使用java socket通信,很基础的。如果采用您说的“服务器推”技术,怎么更改我写的socket呢?那个貌似使用http servlet的哦。。。还是所有有关socket的代码都不能用了,要重写?
谢谢!

#7


引用 2 楼 raistlic 的回复:
[Client A] --call--> [Server] --single.cast--> [Client B] --edt.sync--> [GUI]
[Client A] --call--> [Server] --multi.cast--> [Client A & B] --edt.sync--> [GUI]
[Client A] --call--> [Server] --bro……

我现在使用java socket通信,很基础的。如果采用您说的“服务器推”技术,怎么更改我写的socket呢?那个貌似使用http servlet的哦。。。还是所有有关socket的代码都不能用了,要重写?
谢谢!

#8


引用 7 楼 frr0717 的回复:
引用 2 楼 raistlic 的回复:[Client A] --call--> [Server] --single.cast--> [Client B] --edt.sync--> [GUI]
[Client A] --call--> [Server] --multi.cast--> [Client A & B] --edt.sync--> [GUI]……


Socket 的话,客户端应该专门有一个线程监听 socket 的 getInputStream()
,然后如果有消息从服务器端发过来,解析消息,更新界面。

更新界面的时候需要同步到UI线程(EDT),推荐使用SwingUtilities.invokeLater()

除了这个同步以外,你的问题跟UI关系不大
主要是通信协议设计和客户端线程设计。

#9


引用 8 楼 raistlic 的回复:
引用 7 楼 frr0717 的回复:引用 2 楼 raistlic 的回复:[Client A] --call--> [Server] --single.cast--> [Client B] --edt.sync--> [GUI]
[Client A] --call--> [Server] --multi.cast--> [Client A &……

嗯嗯。。。我最初也是这么设想的。但是请问这个“客户端应该专门有一个线程监听 socket 的 getInputStream()”的线程和SwingWorker有关系吗?

#10


引用 9 楼 frr0717 的回复:
引用 8 楼 raistlic 的回复:引用 7 楼 frr0717 的回复:引用 2 楼 raistlic 的回复:[Client A] --call--> [Server] --single.cast--> [Client B] --edt.sync--> [GUI]
[Client A] --call--> [Server] --multi.cast--> [Cl……


SwingWorker 是为了在后台线程运行一些耗时的工作。

你用Runnable当然也可以,但是SwingWorker提供了方便的最后同步到EDT的方法。

监听socket.getInputStream()的线程可能是这样的:



public class XXX implements Runnable {
  
  private volatile boolean running;
  private Socket socket;

  @Override
  public void run() {
    
    running = true;
    while( running ) {

      // read from socket inputStream
      // analyse message
      // [update ui] / [call ui model]
    }
  }
}


如果你有通信协议之类的设计,它可能还实现其他需要的接口之类的,没有必要用SwingWorker。


#11


如何使用SwingWorker类来实现界面实时强制自动刷新???
引用 10 楼 raistlic 的回复:
引用 9 楼 frr0717 的回复:引用 8 楼 raistlic 的回复:引用 7 楼 frr0717 的回复:引用 2 楼 raistlic 的回复:[Client A] --call--> [Server] --single.cast--> [Client B] --edt.sync--> [GUI]
[Client A] --call--> [Server] ……

1、我看见SwingWorker的先关介绍说,好使的任务包括与数据库通信、想网络请求数据等等。所以我觉得用SwingWorker也行。
2、您说的“SwingWorker提供了方便的最后同步到EDT的方法”是指在doInBackground中的publish将中间结果发送到EDT上的process方法,然后调用done方法进行UI的更新?
3、您上面举得这个例子,我具体还不会怎么融合到我现在的客户端里面。我现在的客户端十一给个的界面,各个界面上有一些事件监听器之类的。如果加上您所说的这个runnable接口,是单独独立出各个窗口类,还是怎么布置?
3、能否把SwingWorker添加到您上面的这个类中呢?可是我觉得SwingWorker就是在多开了一个线程的啊。
哎,我是初学者,现在脑子很乱~~麻烦您多说点儿,O(∩_∩)O谢谢

#12


引用 11 楼 frr0717 的回复:
引用 10 楼 raistlic 的回复:引用 9 楼 frr0717 的回复:引用 8 楼 raistlic 的回复:引用 7 楼 frr0717 的回复:引用 2 楼 raistlic 的回复:[Client A] --call--> [Server] --single.cast--> [Client B] --edt.sync--> [GUI]
[Client A……



呃,这么说吧,我觉得你这里关键的时间点是在

“客户端建立到服务器端的socket连接”的时候。

而这件事一般不是在UI线程中进行的,虽然它可能是点击某个按钮引起的。

比如,你有一个“连接”按钮,在它的 ActionListener 里可能有类似:


public void actionPerformed(ActionEvent e) {
  
  // disable 界面

  new SwingWorker<Void, Void>() {
    
    @Override
    protected Void doInBackground() {
      
      connectServer(); // 这里建立socket连接
      return null;
    }
    
    @Override
    protected void done() {
      
      // enable 界面
    }
  }.execute();
}


而在那个 connectServer 方法中,你建立了socket连接以后,可以起一个专门的线程,这个线程只做一件事,就是反复从socket.getInputStream() 中读取消息。读取的消息可以再交给一个专门分析消息的东西分析,分析完以后用 SwingUtilities.invokeLater() 的方式更新界面。

这个专门读取 socket 输入流的线程,普通的 Runnable 就可以了,没有必要非得是 SwingWorker。

#13


谢谢楼上的解答,按您这么说去做了,可以了~谢谢!

#1


1 在客户端使用定时器每隔一定时间检测服务器

2 实时更新需要服务器支持,搜索comet

#2



[Client A] --call--> [Server] --single.cast--> [Client B] --edt.sync--> [GUI]
[Client A] --call--> [Server] --multi.cast--> [Client A & B] --edt.sync--> [GUI]
[Client A] --call--> [Server] --broad.cast--> [All Clients] --edt.sync--> [GUI]

Observer Design Pattern, 客户端监听服务器上任何它感兴趣的改动,
服务器可以选择对某项改动:

single cast : 确定只有一个客户端对改动感兴趣,发给它
multi cast : 客户端通过某种方式订阅一些“组”,订阅也可以是服务器根据客户端的特性来指定,服务器端根据改动的特点发送给相关订阅的客户端组
broad cast : 服务器端的改动通知所有的客户端,客户端自行判断自己是不是感兴趣

不管是哪一种,客户端需要某种线程(如果是RMI那就是client call back),来监听服务器端的改动,然后如果感兴趣,那就向EDT提交事件,刷新UI。( SwingUtilities.invokeLater(...) )


#3


引用 1 楼 huntor 的回复:
1 在客户端使用定时器每隔一定时间检测服务器

2 实时更新需要服务器支持,搜索comet

请问:那是不是还要用SwingWorker呢?

#4


如果服务器与客户端有建立连接,建议你最好使用消息推送的方式
服务器端有新用户动态,推送给对此相关的客户端!
也可以使用JMS订阅发布方式!

总之办法有很多,跟SwingWorker好像关系不大啊~~~~

#5


引用 4 楼 jia20003 的回复:
如果服务器与客户端有建立连接,建议你最好使用消息推送的方式
服务器端有新用户动态,推送给对此相关的客户端!
也可以使用JMS订阅发布方式!

总之办法有很多,跟SwingWorker好像关系不大啊~~~~

我现在使用java socket通信,很基础的。如果采用您说的“服务器推”技术,怎么更改我写的socket呢?那个貌似使用http servlet的哦。。。还是所有有关socket的代码都不能用了,要重写?
谢谢!

#6


引用 1 楼 huntor 的回复:
1 在客户端使用定时器每隔一定时间检测服务器

2 实时更新需要服务器支持,搜索comet

我现在使用java socket通信,很基础的。如果采用您说的“服务器推”技术,怎么更改我写的socket呢?那个貌似使用http servlet的哦。。。还是所有有关socket的代码都不能用了,要重写?
谢谢!

#7


引用 2 楼 raistlic 的回复:
[Client A] --call--> [Server] --single.cast--> [Client B] --edt.sync--> [GUI]
[Client A] --call--> [Server] --multi.cast--> [Client A &amp; B] --edt.sync--> [GUI]
[Client A] --call--> [Server] --bro……

我现在使用java socket通信,很基础的。如果采用您说的“服务器推”技术,怎么更改我写的socket呢?那个貌似使用http servlet的哦。。。还是所有有关socket的代码都不能用了,要重写?
谢谢!

#8


引用 7 楼 frr0717 的回复:
引用 2 楼 raistlic 的回复:[Client A] --call--> [Server] --single.cast--> [Client B] --edt.sync--> [GUI]
[Client A] --call--> [Server] --multi.cast--> [Client A &amp;amp; B] --edt.sync--> [GUI]……


Socket 的话,客户端应该专门有一个线程监听 socket 的 getInputStream()
,然后如果有消息从服务器端发过来,解析消息,更新界面。

更新界面的时候需要同步到UI线程(EDT),推荐使用SwingUtilities.invokeLater()

除了这个同步以外,你的问题跟UI关系不大
主要是通信协议设计和客户端线程设计。

#9


引用 8 楼 raistlic 的回复:
引用 7 楼 frr0717 的回复:引用 2 楼 raistlic 的回复:[Client A] --call--> [Server] --single.cast--> [Client B] --edt.sync--> [GUI]
[Client A] --call--> [Server] --multi.cast--> [Client A &amp;amp;amp;……

嗯嗯。。。我最初也是这么设想的。但是请问这个“客户端应该专门有一个线程监听 socket 的 getInputStream()”的线程和SwingWorker有关系吗?

#10


引用 9 楼 frr0717 的回复:
引用 8 楼 raistlic 的回复:引用 7 楼 frr0717 的回复:引用 2 楼 raistlic 的回复:[Client A] --call--> [Server] --single.cast--> [Client B] --edt.sync--> [GUI]
[Client A] --call--> [Server] --multi.cast--> [Cl……


SwingWorker 是为了在后台线程运行一些耗时的工作。

你用Runnable当然也可以,但是SwingWorker提供了方便的最后同步到EDT的方法。

监听socket.getInputStream()的线程可能是这样的:



public class XXX implements Runnable {
  
  private volatile boolean running;
  private Socket socket;

  @Override
  public void run() {
    
    running = true;
    while( running ) {

      // read from socket inputStream
      // analyse message
      // [update ui] / [call ui model]
    }
  }
}


如果你有通信协议之类的设计,它可能还实现其他需要的接口之类的,没有必要用SwingWorker。


#11


如何使用SwingWorker类来实现界面实时强制自动刷新???
引用 10 楼 raistlic 的回复:
引用 9 楼 frr0717 的回复:引用 8 楼 raistlic 的回复:引用 7 楼 frr0717 的回复:引用 2 楼 raistlic 的回复:[Client A] --call--> [Server] --single.cast--> [Client B] --edt.sync--> [GUI]
[Client A] --call--> [Server] ……

1、我看见SwingWorker的先关介绍说,好使的任务包括与数据库通信、想网络请求数据等等。所以我觉得用SwingWorker也行。
2、您说的“SwingWorker提供了方便的最后同步到EDT的方法”是指在doInBackground中的publish将中间结果发送到EDT上的process方法,然后调用done方法进行UI的更新?
3、您上面举得这个例子,我具体还不会怎么融合到我现在的客户端里面。我现在的客户端十一给个的界面,各个界面上有一些事件监听器之类的。如果加上您所说的这个runnable接口,是单独独立出各个窗口类,还是怎么布置?
3、能否把SwingWorker添加到您上面的这个类中呢?可是我觉得SwingWorker就是在多开了一个线程的啊。
哎,我是初学者,现在脑子很乱~~麻烦您多说点儿,O(∩_∩)O谢谢

#12


引用 11 楼 frr0717 的回复:
引用 10 楼 raistlic 的回复:引用 9 楼 frr0717 的回复:引用 8 楼 raistlic 的回复:引用 7 楼 frr0717 的回复:引用 2 楼 raistlic 的回复:[Client A] --call--> [Server] --single.cast--> [Client B] --edt.sync--> [GUI]
[Client A……



呃,这么说吧,我觉得你这里关键的时间点是在

“客户端建立到服务器端的socket连接”的时候。

而这件事一般不是在UI线程中进行的,虽然它可能是点击某个按钮引起的。

比如,你有一个“连接”按钮,在它的 ActionListener 里可能有类似:


public void actionPerformed(ActionEvent e) {
  
  // disable 界面

  new SwingWorker<Void, Void>() {
    
    @Override
    protected Void doInBackground() {
      
      connectServer(); // 这里建立socket连接
      return null;
    }
    
    @Override
    protected void done() {
      
      // enable 界面
    }
  }.execute();
}


而在那个 connectServer 方法中,你建立了socket连接以后,可以起一个专门的线程,这个线程只做一件事,就是反复从socket.getInputStream() 中读取消息。读取的消息可以再交给一个专门分析消息的东西分析,分析完以后用 SwingUtilities.invokeLater() 的方式更新界面。

这个专门读取 socket 输入流的线程,普通的 Runnable 就可以了,没有必要非得是 SwingWorker。

#13


谢谢楼上的解答,按您这么说去做了,可以了~谢谢!