Maxi Krautzik
Maxi Krautzik

Reputation: 3

Android Studio keeps saying, that I need to declare a final variable

Hey I´m new in programming, especially in java and xml. I want to make a game where a progressbar show the time that is left for a task to do but Android Studio keeps saying, that I need to declare a final variable to use i++ and mProgressBar.setProgress (i); because its in a inner Class. But as far as I know a final variable cannot change it´s value. What should I change to make the code work again?

@Override
public void onResume() {
    super.onResume();

    View decorView = getWindow().getDecorView();
    decorView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE
            | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
            | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
            | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
            | View.SYSTEM_UI_FLAG_FULLSCREEN
            | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);
    final ImageView ball = (ImageView) findViewById(R.id.ball);
    ball.setOnTouchListener(new View.OnTouchListener()
    {
        PointF DownPT = new PointF(); // Record Finger Position When Pressed Down
        PointF StartPT = new PointF(); // Record Start Position of 'ball'

        @Override
        public boolean onTouch(View v, MotionEvent event)
        {
            int eid = event.getAction();
            switch (eid)
            {
                case MotionEvent.ACTION_MOVE :
                    PointF mv = new PointF( event.getX() - DownPT.x, event.getY() - DownPT.y);
                    ball.setX((int)(StartPT.x+mv.x));
                    ball.setY((int)(StartPT.y+mv.y));
                    StartPT = new PointF(ball.getX(), ball.getY() );
                    break;
                case MotionEvent.ACTION_DOWN :
                    DownPT.x = event.getX();
                    DownPT.y = event.getY();
                    StartPT = new PointF(ball.getX(), ball.getY() );
                    break;
                case MotionEvent.ACTION_UP :
                    // Nothing have to do
                    break;
                default :
                    break;
            }
            return true;
        }
    });
    ProgressBar mProgressBar;
    CountDownTimer mCountDownTimer;
    int i=0;

    mProgressBar=(ProgressBar)findViewById(R.id.progressBartime);
    mProgressBar.setProgress(i);
    mCountDownTimer=new CountDownTimer(3000,1000) {

        @Override
        public void onTick(long millisUntilFinished) {
            Log.v("Log_tag", "Tick of Progress"+ i+ millisUntilFinished); //i needs to be declared as final
            i++; //i needs to be declared as final
            mProgressBar.setProgress(i); //mProgressBar needs to be declared as final

        }


        @Override
        public void onFinish() {
            //Do what you want
            i++;  //i needs to be declared as final
            mProgressBar.setProgress(i); //mProgressBar needs to be declared as final
        }
    };
    mCountDownTimer.start();
}

}

Upvotes: 0

Views: 1922

Answers (1)

Ryan
Ryan

Reputation: 1883

Because you are using an inner class it cannot access a mutable variable outside of itself. Try using AtomicInteger as that can be set as final, so you would do something like this:

// Outer class (where I is currently defined)
final AtomicInteger i = new AtomicInteger();

//Inner class (within the onTick function)
i.incrementAndGet();

Then to retrieve the value use i.get()

For your particular case you can actually set the i variable inside the inner class.

e.g.

CountDownTimer mCountDownTimer;

final ProgressBar mProgressBar=(ProgressBar)findViewById(R.id.progressBartime);
mProgressBar.setProgress(i);
mCountDownTimer=new CountDownTimer(3000,1000) {
    int i = 0;

    @Override
    public void onTick(long millisUntilFinished) {
        Log.v("Log_tag", "Tick of Progress"+ i+ millisUntilFinished); //i needs to be declared as final
        i++; 
        mProgressBar.setProgress(i); //mProgressBar needs to be declared as final

    }


    @Override
    public void onFinish() {
        //Do what you want
        i++;  
        mProgressBar.setProgress(i); //mProgressBar needs to be declared as final
    }
};

As mProgressBar doesn't need to be mutable, you can set that as a final variable without any problems as it is.

edit: update why final can be used

The reason mProgressBar can be set as a final is that it is an object, with final variables the reference of the object cannot change, but any values that aren't set final inside the object can change, that's why the setProgress will work. However, with primitive variables they can only be set once, this is for performance gains.

This has a good explanation as to why you cannot modify a non-final local variable from a local class.

Local classes can most definitely reference instance variables. The reason they cannot reference non final local variables is because the local class instance can remain in memory after the method returns. When the method returns the local variables go out of scope, so a copy of them is needed. If the variables weren’t final then the copy of the variable in the method could change, while the copy in the local class didn’t, so they’d be out of synch.

Upvotes: 3

Related Questions