Reputation: 3
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
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