从父级向 public void 运行() 传递参数

Passing parameters to public void run() from the parent

我有 50% 的绝望 :P。我尝试(在开始时)从线程代码更新 GUI,并得到 NullException。阅读了一段时间后,我了解到 Thread 淹没了 JavaFX 应用程序 window 为了让我从 Thread 更新 GUI,我需要使用以下代码:

Platform.runLater(new Runnable() {
            @Override public void run() {

            //Update UI here     
            for (int i=0; i<2000;i++)
                {
                 MyMainClass.leftPaneTextArea.appendText("Goodi!\n");
                }

            }
        });

所以我确实使用了这段代码,它确实允许我编辑我的主要 class 的 GUI。但是,我的问题很简单。 => 这段代码,我 运行ning 来自一个线程,是一个位于 public void 运行()(线程 I 运行代码来自)。它看起来像这样:

@Override
    public void run() {

    String tmpVar;

    ... (Some code)
    ... (Some code)
    ... (Some code)

        Platform.runLater(new Runnable() {
            @Override public void run() {

            //Update UI here     
            for (int i=0; i<2000;i++)
                {
                 MyMainClass.leftPaneTextArea.appendText("Goodi!\n");
                }

            }
        });

    ... (Some code)
    ... (Some code)
    ... (Some code)
}

如何将参数从父级的 public void 运行() 传递给这个?。 例如,字符串 tmpString(我想传递给它)。

请注意,如果我在 public void 运行() 之外将其声明为静态(例如)=> 我 运行 很多线程,因此更新一个static var 可能并不总是准确的(因为很多线程会同时更新它)

谢谢!

你想做的是反对压倒一切的规则。 如果您要在 run() 方法中传递任何参数,您实际上是在重载 run() 方法,并且无论如何都不会调用它 创建新线程时,调用无参数 run() 方法。

我建议将信息存储在 static 上下文中的其他地方,然后在 run() 方法中检索它。

基本上,您需要考虑将参数传递给 Runnable 对象,而不是传递给 run() 方法。

如果将匿名 class 设为内部 class,它就变得很清楚了:

@Override
public void run() {

    String tmpVar;

    // ... (Some code)
    // ... (Some code)
    // ... (Some code)

        Platform.runLater(new Updater(tmpVar));

    // ... (Some code)
    // ... (Some code)
    // ... (Some code)
}

// ...

public static class Updater implements Runnable {

    private final String var ;

    public Updater(String var) {
        this.var = var ;
    }



    @Override 
    public void run() {

        // Access var here

        for (int i=0; i<2000;i++){
            MyMainClass.leftPaneTextArea.appendText("Goodi!\n");
        }

    }
}

现在,如果 tmpVarfinal 或 "effectively final1",那么它将与您的匿名内部 class 一起工作,并且基本上被翻译成完全相同的东西正如上面的内部 class (换句话说,匿名内部 class 得到一个隐式字段,该字段填充了最终变量的值):

@Override
public void run() {

    final String tmpVar = ...;

    // ... (Some code)
    // ... (Some code)
    // ... (Some code)

    Platform.runLater(new Runnable() {
        @Override public void run() {

        // access tmpVar here:

        for (int i=0; i<2000;i++)
            {
             MyMainClass.leftPaneTextArea.appendText("Goodi!\n");
            }

        }
    });

    // ... (Some code)
    // ... (Some code)
    // ... (Some code)
}

语言设计者 可以 实际上已经用非最终变量完成了这项工作,但认为结果太混乱了。将会发生的情况是,它会被翻译成上面看到的相同的内部 class:换句话说,tmpVarcurrent 值将被隐式传递到匿名内部 class 中的一个字段。这将是一个全新的变量,具有不同的范围,与您正在访问的变量不同,它的值将是匿名内部 [=] 时 tmpVar 值的 "snapshot" 51=] 被创建。看似一个变量实际上指的是两个不同的变量 可能具有不同的值 被认为太混乱且容易出错。

但是,如果 tmpVar 不是最终的(或实际上是最终的):即您要多次为其赋值,您可以 明确地 "snapshot" 变量的值:

@Override
public void run() {

    String tmpVar ;

    // ... (Some code)
    // ... (Some code)
    // ... (Some code)

    final String varCopy = tmpVar ;

    Platform.runLater(new Runnable() {
        @Override public void run() {

        // access varCopy here:

        for (int i=0; i<2000;i++)
            {
             MyMainClass.leftPaneTextArea.appendText("Goodi!\n");
            }

        }
    });

    // ... (Some code)
    // ... (Some code)
    // ... (Some code)
}

(1) "Effectively final" 表示变量被赋值恰好一次。等价地,这意味着您可以声明它 final 而不会产生任何编译错误。

James_D 发布的一个选项是在内部 class(匿名或非匿名)中使用 final var

其他选项,例如 new MyRunnable(someString) 或使用 Consumer<T> 您可以找到 here

您可以随时使用 getter...

public class YourClass {
    private String myVar;

    public void do something(String aVal) {
        myVar= "Value you want to pass";

        this.runOnUiThread(new Runnable() {
            @Override
            public void run() {    
                Log.d("TAG",getMyVar());
            }
        });
    }

    private String myVar(){
        return myVar;
    }
}