Reputation: 16978
Kind of a silly problem I'm facing here... Basically I'm in a For-loop and within this loop I'm always calling a function to make a button. But in this function I want to pass the loop iterator as it's changing to differentiate the buttons. But then it tells me I need to make the loop iterator "final" which means it doesn't change!
Well my problem will make more sense with some skeleton code:
for(int i = 0; i < appList.size(); i++) {
//some other stuff including creating the below button 'btn'
btn.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
//set some attribute based on i
//but when I do this it only sets based on the greatest value of i (!)
}
});
}
Meh kinda silly problem I know... I'm new to Java though!
Cheers.
Upvotes: 4
Views: 1437
Reputation: 14162
Consider this bit of silly example code:
int i = 0;
obj.invokeThunkAfter10Seconds(new ThunkObject() {
public void thunk() {
System.out.println(i);
}
}
i = 1;
The ThunkObject
holds a reference to i
, but i
can change, which makes the output unpredictable and depends on when i
is changed and when thunk
is invoked.
Because Java doesn't have proper closures (by design, see Cannot refer to a non-final variable inside an inner class defined in a different method), you are explicitly not allowed to capture non-final (i.e. changable) variables like this.
Instead you must declare the variable final
, meaning it's initialized and then is not changable. This means you can never change i
after it has been captured by the inner class.
final int i = 0;
obj.invokeThunkAfter10Seconds(new ThunkObject() {
public void thunk() {
System.out.println(i);
}
}
// Can't change i here. It will forever now be 0.
In your example you can't just set i
to be final, because you do want to change the value on each loop iteration. Instead you can create a copy of the value in a final variable:
for(int i = 0; i < appList.size(); i++) {
//some other stuff including creating the below button 'btn'
final int capturedI = i;
btn.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
//set some attribute based on capturedI
}
});
}
Upvotes: 1
Reputation: 105220
for(int i = 0; i < appList.size(); i++) {
final int _i = i;
btn.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
// use _i instead of i
}
});
}
Upvotes: 4