0

我正在使用 OpenCYC api(不是太常见,但除此之外),我正在尝试创建一个AccessObject名为ao. 问题是,无论出于何种原因,AccessObject都无法在主 Java Swing 事件线程中实例化 an。

因此,作为一种解决方法,我创建了另一个线程,它只是AccessObject在它的run()方法中实例化一个,并且还为它提供了一个 getter 来返回它。

所以这就是我的调用代码:

// do something with code

AccessObject ao;
AccessObjectInstantiateThread aoThread = new AccessObjectInstantiationThread();
aoThread.start();

while(ao == null) // while loop to ensure we "wait" for aoThread to finish
{
     ao = aoThread.getAoObject();
}

// Then use ao however you want

现在这段代码可以工作了,但看起来很荒谬。有没有更好的方法来做到这一点?请记住,我无法AccessObject在主 java 事件线程下实例化一个。

非常感谢你,里奇。

4

3 回答 3

4
  1. doInBackground()在 SwingWorker 对象中实例化它,并在完成该方法之前检查一个有效的对象。
  2. 将 PropertyChangeWorker 添加到侦听 SwingWorker.StateValue.DONE 的 SwingWorker,然后将对象传递给您的 Swing 程序。

例如,

class MySwingWorker extends SwingWorker<AccessObject, Void> {
  public AccessObject doInBackground() throws Exception {
    // do whatever needed to create your AccessObject and check its completion

    // return your AccessObject
  }
}

在您的 Swing 代码中:

final MySwingWorker mySwingWorker = new MySwingWorker();

mySwingWorker.addPropertyChangeListener(new PropertyChangeListener() {
  public void propertyChanged(PropertyChangeEvent pcEvt) {
    if (pcEvt.getNewValue() == SwingWorker.StateValue.DONE) {
      try {
        ao = mySwingWorker.get(); // ao is an AccessObject class field

        // you can use ao here

      }  catch (whaeverExceptionYouAreTrapping e) {
        // do something with exception
      }
    }
  }
});
mySwingWorker.execute();

注意,代码注释经过测试或编译。


根据 JB Nizet 的建议进行编辑,您也可以在 Swing 代码中简单地做一个匿名内部类并跳过 PropertyChangeListener:

new SwingWorker<AccessObject, Void>() {
  public AccessObject doInBackground() throws Exception {
    // do whatever needed to create your AccessObject and check its completion

    // return your AccessObject
  }

  public void done() {
    try {
      ao = mySwingWorker.get(); // ao is an AccessObject class field

      // you can use ao here

    }  catch (whaeverExceptionYouAreTrapping e) {
      // do something with exception
    }
  }
}.execute();
于 2013-07-24T21:47:30.600 回答
1

您的代码可能无法正常工作。你至少应该如下声明你的变量:

易失性访问对象 ao;

原因是,您的 EDT 线程可能会缓存 ao 变量的值作为优化,并且可能看不到 ao 被分配给新值。

我希望这段代码在你应用程序的开头,用户不会看到 UI 没有响应。

于 2013-07-24T22:10:34.510 回答
0

ao理想情况下,您将在启动线程(在方法中)上创建 AccessObject ,main()并且在您拥有之后才启动您的 UI(EventQueue.InvokeLater使用包含类似内容的可运行对象new JFrame)。

做不到这一点,就会变得ao不稳定。您的实例化代码应直接设置此值,而不是为“get”方法而烦恼。它可能还应该调用带有可运行的 InvokeLater 来重新调整显示——也许启用一两个按钮并向用户发送一条消息,告诉用户现在可以实现以前不可能的事情。

任何代码访问ao都必须准备好它可能为空的事实;你的 GUI 必须双向工作,让用户清楚地了解它的情况。每项检查或参考应类似于:

final AccessObject  local_ao = ao;
if (local_ao != null)  {
    // Do things.  USE local_ao, NOT oa!!!
}

简而言之,始终使用 local_ao,它不会改变。请记住,ao可以并且随时会更改的值。正如您所描述的,它只会从 null 更改为非 null,并且只会更改一次,但这可能会随着您的代码的发展而改变。(如果它不会进化,我的第一个建议可能是最好的。)

您的 UI (EventQueue) 代码不应等待任何事情。线程很痛苦,我会在 UI 上稍微延迟一下,而不是每天使用线程。但是您已经为线程付出了代价,因此您还不如物有所值。

于 2013-07-25T18:51:25.783 回答