skip to Main Content

Hello guys I want to place the following code in a new thread that is different from the ui thread but android studio gives an error that the variable needs to be declared final. when i declare the variable final it crashes my app. Please how can i start a new thread without declaring the variable 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);
            }
        }
    }

I am trying to achieve something like this without make my variable final

  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();

    }

2

Answers


  1. You don’t have to make position, rowImpact, or takenPawn final.
    But you can’t change it before your new Thread(new Runnable()..
    If you have to it has to be final.. why? here is a detailed description: https://blog.brendanlacanette.com/2015/08/variable-is-accessed-within-inner-class.html

    To solve this you have some possibilities:

    1. make a new final variable, and use this in your Runnable

      final int finalPosition = position;

    2. put them in an array, and use for example params[0] in your Runnable.
      I don’t like this approach

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

    3. create a wrapper object for your parameters

        //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 
    
    Login or Signup to reply.
  2. The code you’ve shown here doesn’t require final, at least when compiling in Java 8+, which allows anonymous classes to reference effectively-final variables.

    The only reason you wouldn’t be able to reference the parameters inside the anonymous class is if there is code which reassigns them (either inside or outside the anonymous class): without reassignment, the parameters would be considered effectively final.

    If there is other code in this method which reassigns these variables, the simple answer is to extract either the code you’ve shown or the code you’ve not into another method:

    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.
    }
    
    

    Or you can declare extra variables with the same values as the parameters, and reference these inside the thread:

    int positionCopy = position;
    // etc.
    

    Or you can declare the Runnable with a named class, and give it a constructor and explicit fields:

    class CheckUpTakingRunnable implements Runnable {
      private final int position;
      // etc.
    
      CheckUpTakingRunnable(int position /* etc */) {
        this.position = position;
      }
    
      // run() method.
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search