【问题标题】:SWTException: Invalid thread accessSWTException:无效的线程访问
【发布时间】:2014-12-16 08:37:48
【问题描述】:

如果我第一次在空工作区中运行它,我正在使用一个创建 java 项目的向导,并得到一个无效的线程访问异常。我尝试实现类似于JavaProjectWizard 的向导,但我不需要第二页,所以我尝试从第一页执行完成并提前初始化第二页:

import org.eclipse.jdt.ui.wizards.NewJavaProjectWizardPageTwo;
import org.eclipse.jface.wizard.Wizard;
import org.eclipse.ui.INewWizard;

public class SomeNewWizard
    extends Wizard
    implements INewWizard {

    private SomeWizardPageTwo javaWizardPageTwo;

    @Override
    public void addPages() {
            if (javaWizardPageTwo == null)
                    someWizardPageTwo = new SomeWizardPageTwo(newSeeAppWizardPageOne);
    }

    @Override
    public boolean performFinish() {
/*line 109*/someWizardPageTwo .createProvisonalProject();
            final IWorkspaceRunnable op = new IWorkspaceRunnable() {
                    public void run(IProgressMonitor monitor)
                            throws CoreException, OperationCanceledException {
                            try {
                                    someWizardPageTwo.performFinish(new SubProgressMonitor(monitor, 1));
                            }
                            catch (InterruptedException e) {
                                    throw new OperationCanceledException(e.getMessage());
                            }
                            finally {
                                    monitor.done();
                            }
                    }
            };
            try {
                    rule = null;
                    Job job = Job.getJobManager().currentJob();
                    if (job != null)
                            rule = job.getRule();
                    IRunnableWithProgress runnable = new IRunnableWithProgress() {
                            @Override
                            public void run(IProgressMonitor monitor)
                                    throws InvocationTargetException, InterruptedException {
                                    try {
                                            JavaCore.run(op, rule, monitor);
                                    }
                                    catch (OperationCanceledException e) {
                                            throw new InterruptedException(e.getMessage());
                                    }
                                    catch (CoreException e) {
                                            throw new InvocationTargetException(e);
                                    }
                            }
                    };
                    getContainer().run(true, true, runnable);
            }
            catch (InvocationTargetException e) {
                    handleFinishException(getShell(), e);
                    return false;
            }
            catch (InterruptedException e) {
                    return false;
            }
            return true;
    }

public class SomeWizardPageTwo
    extends NewJavaProjectWizardPageTwo
{

    private NewJavaProjectWizardPageOne mainPage;


    public SomeWizardPageTwo(NewJavaProjectWizardPageOne mainPage)
    {
        super(mainPage);
        this.mainPage = mainPage;
    }


    @Override
    public IProject createProvisonalProject()
    {
        return super.createProvisonalProject();
    }


    @Override
    protected IWizardContainer getContainer()
    {
        if (mainPage == null)
            return null;
        return mainPage.getWizard().getContainer();
    }
}

可以在here找到堆栈跟踪。

问题的根源似乎是ImageDescriptorRegistry 是从错误的线程创建的,因为对应的IRunnableWithProgress 运行forked。但我想知道为什么它对普通的JavaProjectWizard 有效呢?主要问题是:如何让它为我的向导工作?

【问题讨论】:

    标签: java concurrency swt wizard eclipse-plugin


    【解决方案1】:

    Display.checkDevice 中没有错误。

    您对NewJavaProjectWizardPageTwo.performFinish 的调用正在后台线程中运行,但代码使用的是ImageDescriptorRegistry,需要在用户界面线程上进行初始化。

    这是间歇性的,因为有时您所做的其他事情已经初始化了注册表。

    【讨论】:

    • 很好地解释了原因和异常。
    • 我使用 setErrorMessage(message)setMessage(message, DialogPage.WARNING) 方法来加载警告/错误图标。我的阅读是这是问题的根源。
    • 但我无法解释的是原始的 eclipse 向导也加载了一个错误图标,运行分叉的完成操作并且不抛出异常。
    • 我的建议是错误的。即使我省略了上述方法,我也会遇到异常。
    • 普通的JavaProjectWizard 在向导中使用来自 Java 映像注册表的映像 - 这将在完成运行之前初始化注册表。
    【解决方案2】:

    getContainer().run(true, true, runnable); 导致 runnable 在单独的线程中执行。因此,第一个参数fork 负责。 调用javaWizardPageTwo.performFinish()尝试访问UI线程,导致无效线程访问异常。

    如果将fork参数设置为false,代码会在当前线程上执行。

    你为什么不直接打电话给javaWizardPageTwo.performFinish()

    【讨论】:

    • 我基于原始的 New JavaProject Wizard 构建了我的代码。对应部分在NewElementWizard。有getContainer().run(canRunForked(), true, runnable);canRunForked() 总是返回true。
    • 如果我直接打电话给javaWizardPageTwo.performFinish(),我就不可能使用IProgressMonitor
    • 您关于 eclipse 如何分叉线程的提示真的很有帮助 - 请继续在您的下一个答案中提供更多信息,这真的很棒!!!
    • @MartinFrank 感谢您的反馈,我很高兴回答对您有所帮助。
    猜你喜欢
    • 1970-01-01
    • 2015-04-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多