与 Java/J2ME 中的 UI 线程交互
-
08-07-2019 - |
题
我正在编写一个 J2ME 应用程序。其中一个部分是定期轮询目录内容,如果有任何新内容,则将它们绘制在屏幕上。我通过让 UI 表单启动一个轮询线程,并用一个指向自身的指针来完成此操作,当轮询线程发现某些内容时,它会回调到表单并调用同步方法来更新其显示。这似乎工作正常。
我的问题是这样的。在 C#/.NET 中,我知道让非 UI 线程更新 UI 并不好,处理此问题的正确方法是将其委托给 UI 线程。
例如。下列:
public void DoSomeUIThing()
{
if (this.uiComponent.InvokeRequired)
{
this.uiComponent.Invoke(someDelegateThatCallsBackToThis);
}
else
{
this.uiComponent.Text = "This is the update I want to happen";
}
}
是否有 J2ME 等效方法来管理此流程?Java 怎么样?还是 Java/J2ME 在这方面表现得更好?如果没有,这是如何完成的?
[编辑] 看来 Swing 通过 SwingUtilities.invokeLater() 和 invokeAndWait() 方法支持我所询问的内容。J2ME 有等效的框架吗?
解决方案
关于Java,你所描述的看起来像 SwingWorker(工作线程).
当 Swing 程序需要执行长时间运行的任务时,它通常会使用其中一个工作线程,也称为后台线程。
Swing 程序包括以下几种线程:
- 初始线程,执行初始应用程序代码的线程。
- 事件调度线程,所有事件处理代码都在其中执行。大多数与 Swing 框架交互的代码也必须在此线程上执行。
- 工作线程,也称为后台线程,执行耗时的后台任务。
单线程规则:
一旦实现了 Swing 组件,所有可能影响或依赖于该组件状态的代码都应该在事件分派线程中执行。
当在 J2EE 上下文中使用时,您需要小心 从 EJB 引用 SwingWorker.
关于 J2ME, ,这取决于您是否将应用程序开发为将在任何支持 MIDP 的设备上运行的标准 MIDlet,或者 例如 作为 RIMlet,一种基于 CLDC 的应用程序,使用 BlackBerry 特定的 API,因此只能在 BlackBerry 设备上运行。
因为与 MIDP 的 UI 类不同,RIM 与 Swing 类似,因为 UI 操作发生在事件线程上,而事件线程不像 MIDP 中那样是线程安全的。要在事件线程上运行代码,应用程序必须获得事件对象的锁,或者使用invokeLater() 或invokeAndWait()——这对开发人员来说是额外的工作,但复杂性是有代价的。
其他提示
Java ME有很多个人资料。如果你的意思是MIDP,那么Display.runSerially
就是你想要的。
对于AWT(Swing),你会使用EventQueue.invokeLater
(SwingUtilities.invokeLater
只是因为Java 1.1没有EventQueue
方法 - 1.2即将庆祝它的十岁生日)。对于Common DOM API,请使用DOMService.invokeLater
。
无论GUI API如何声称线程安全,它们可能都是错误的(在JDK7中删除了一些Swing的声明,因为它们不可实现)。在任何情况下,应用程序代码都不太可能是线程安全的。
对于j2me应用程序,您可能希望保持简单。主要的是仅在事件线程中触摸UI组件。这样做的直接方法是使用 invokeLater或invokeAndWait 。根据您的库,您将无法访问除此之外的任何内容。一般情况下,如果您的平台没有提供这些,它可能等同于没有线程支持而不是问题。例如,黑莓确实支持它。
如果在SWT下开发,则可以通过Display对象的asyncExec()方法实现。您传递实现Runnable的对象,以便UI线程执行在其他线程中完成的更改。
这是借鉴此处
的示例public void itemRemoved(final ModelEvent me)
{
final TableViewer tableViewer = this.viewer;
if (tableViewer != null)
{
display.asyncExec(new Runnable()
{
public void run()
{
tableViewer.remove(me.getItem());
}
}
}
}
我可以证明MIDP UI工具包确实是线程安全的,因为我在大多数制造商生产的数百万部手机上都运行了大型的带有复杂GUI的MIDlet,而且我从未见过这方面的问题。