【问题标题】:Start a new thread without making variables final启动一个新线程而不使变量最终
【发布时间】:2021-11-12 03:48:47
【问题描述】:

大家好,我想将以下代码放在与 ui 线程不同的新线程中,但 android studio 给出了一个错误,即需要将变量声明为 final。当我声明变量 final 时,它会使我的应用程序崩溃。请问如何在不声明变量 final 的情况下启动新线程。

public void checkUpTaking(int position, int rowImpact, int takenPawn) { //taken pawn: -1 = brown, 1 = white
        if (position > 10) { //if you'll try to take from the last row - array out of bounds
            if (position % 5 != 0 && playableTile[position - 1 - 4 - rowImpact].getIsTaken() == takenPawn &&
                    playableTile[position - 1 - 9].getIsTaken() == 0) {
                checkTreeNodes(position, position - 9, position-4-rowImpact); //checking possible mandatory moves before clicking pawn
            }
            if ((position - 1) % 5 != 0 && playableTile[position - 1 - 5 - rowImpact].getIsTaken() == takenPawn &&
                    playableTile[position - 1 - 11].getIsTaken() == 0) {
                checkTreeNodes(position, position - 11, position-5-rowImpact);
            }
        }
    }

我正在尝试在不使我的变量成为最终变量的情况下实现这样的目标

  public void checkUpTaking(int position, int rowImpact, int takenPawn) { //taken pawn: -1 = brown, 1 = white
        new Thread(new Runnable() {
            @Override
            public void run() {
                if (position > 10) { //if you'll try to take from the last row - array out of bounds
                    if (position % 5 != 0 && playableTile[position - 1 - 4 - rowImpact].getIsTaken() == takenPawn &&
                            playableTile[position - 1 - 9].getIsTaken() == 0) {
                        checkTreeNodes(position, position - 9, position-4-rowImpact); //checking possible mandatory moves before clicking pawn
                    }
                    if ((position - 1) % 5 != 0 && playableTile[position - 1 - 5 - rowImpact].getIsTaken() == takenPawn &&
                            playableTile[position - 1 - 11].getIsTaken() == 0) {
                        checkTreeNodes(position, position - 11, position-5-rowImpact);
                    }
                }
            }
        }).start();

    }

【问题讨论】:

  • "without make my variable final" 我不明白为什么你需要将它们设为final。是否还有其他代码未显示重新分配参数的位置?
  • 是的,我正在尝试制作跳棋游戏,但我正在尝试解决 Anr 错误。所以我试图减少我的主线程上的工作量。我的代码很长,它的主体受限于 stackoverflow
  • 但是您在此处显示的代码doesn't require final。如果此方法中有其他代码重新分配这些变量,简单的答案是提取您显示的代码或您没有提取到另一个方法中的代码。
  • 为什么不能将变量声明为final?我不确定android是否有与java不同的规则。您可以将 final 放在方法参数上。

标签: java multithreading android-studio arraylist


【解决方案1】:

您在此处显示的代码 doesn't require final,至少在 Java 8+ 中编译时,它允许匿名类有效地引用最终变量。

您无法在匿名类中引用参数的唯一原因是如果有代码重新分配它们(在匿名类内部或外部):如果不重新分配,参数将被视为有效最终

如果此方法中有其他代码重新分配这些变量,简单的答案是提取您显示的代码或您没有提取到另一个方法中的代码:

public void checkUpTaking(int position, int rowImpact, int takenPawn) {
  // The code creating the thread.

  restOfTheMethodBody(position, rowImpact, takenPawn);
}

private void restOfTheMethodBody(int position, int rowImpact, int takenPawn) {
  // The code which needs to update position/rowImpact/takenPawn.
}

或者您可以声明与参数具有相同值的额外变量,并在线程内引用它们:

int positionCopy = position;
// etc.

或者你可以用一个命名类声明Runnable,并给它一个构造函数和显式字段:

class CheckUpTakingRunnable implements Runnable {
  private final int position;
  // etc.

  CheckUpTakingRunnable(int position /* etc */) {
    this.position = position;
  }

  // run() method.
}

【讨论】:

    【解决方案2】:

    您不必将 position、rowImpact 或 takePawn 设置为最终状态。 但是你不能在你的 new Thread(new Runnable().. 如果必须,它必须是最终的..为什么?这里有详细说明:https://blog.brendanlacanette.com/2015/08/variable-is-accessed-within-inner-class.html

    要解决这个问题,您有一些可能性:

    1. 创建一个新的 final 变量,并在你的 Runnable 中使用它

      final int finalPosition = 位置;

    2. 将它们放在一个数组中,并在 Runnable 中使用例如 params[0]。 我不喜欢这种方法

      int[] params = new int[]{position, rowImpact,takenPawn};

    3. 为您的参数创建一个包装器对象

        //as own class or even as inner class
        public class CheckupParameters
        {
            public CheckupParameters(int position, int rowImpact, int takenPawn)
            {
                this.position = position;
                this.rowImpact = rowImpact;
                this.takenPawn = takenPawn;
            }
            
            int position;
            int rowImpact;
            int takenPawn;
        }
        
        // in then before your Thread...
        CheckupParameters checkupParameters = new CheckupParameters(position, rowImpact,     takenPawn);
        
        // and in your Runnable you can access
        params.position 
    

    【讨论】:

    • “在我看来你的代码编译”的意见不应该出现:它编译,或者它不编译:)
    • @AndyTurner 谢谢你的建议。它在我的机器上编译。但我不确定为什么。我记得以前我经常不得不将变量 final 用于内部类。但是现在我的 IDE 没有抱怨。这在更新的 Java 版本中是否发生了变化?不确定
    • 从 Java 8 开始,您不需要显式声明局部变量 final,它引入了实际上是 final 的概念。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-06-25
    • 1970-01-01
    • 1970-01-01
    • 2012-05-06
    • 2014-03-19
    相关资源
    最近更新 更多